public async Task <IActionResult> GetEntries(TimeclockEntryQueryDto dto)
        {
            //ensure the entry belongs to the current user and that the current user is still in the specified patrol
            if (User.PatrolIds().Any(x => x == dto.PatrolId) &&
                (dto.UserId == User.UserId() ||
                 User.RoleInPatrol(dto.PatrolId).CanMaintainTimeClock()))    //or the user is an admin
            {
                var entries = await _timeEntryRepository.GetTimeEntries(dto.PatrolId, dto.UserId, dto.From, dto.To);

                return(Ok(entries));
            }
            else
            {
                return(Forbid());
            }
        }
        async Task <TimeEntrySummaryReportItem[]> ITimeEntryService.GenerateSummaryReport(GenerateTimeEntrySummaryReportQuery query)
        {
            var operation        = query.IncludeTimeEntriesOfAllUsers ? Operation.ReadAll : Operation.Read;
            var currentPrincipal = await currentUserResolver.ResolveCurrentClaimsPrincipalAsync();

            await authorizationService.AuthorizeResourceType(currentPrincipal, operation, typeof(TimeEntry));

            Check.NotNull(query, "Query can not be null.");
            await validationService.Validate(query);

            var timeEntries = timeEntryRepository.GetTimeEntries();

            if (!query.IncludeTimeEntriesOfAllUsers)
            {
                var currentUser = await currentUserResolver.ResolveAsync();

                timeEntries = timeEntries.Where(te => te.OwnerId == currentUser.Id);
            }

            if (!string.IsNullOrWhiteSpace(query.QueryString))
            {
                try
                {
                    var parseResult = await queryParser.ApplyQuery(timeEntries, query.QueryString);

                    timeEntries = parseResult.Results;
                }
                catch (Exception ex)
                {
                    throw new ValidationException("Invalid query string.", ex);
                }
            }
            timeEntries = timeEntries
                          .OrderBy(te => te.OwnerId)
                          .ThenBy(te => te.Date);

            var resultIndex = new Dictionary <string, List <TimeEntry> >();

            foreach (var entry in timeEntries)
            {
                var serializedIndex = SerializeIndex(entry.OwnerId, entry.Date);
                if (!resultIndex.ContainsKey(serializedIndex))
                {
                    resultIndex.Add(serializedIndex, new List <TimeEntry>());
                }

                resultIndex[serializedIndex].Add(entry);
            }

            return(resultIndex.Values.Select(r =>
            {
                var firstTimeEntry = r.First();

                var reportItem = new TimeEntrySummaryReportItem()
                {
                    OwnerId = firstTimeEntry.OwnerId,
                    OwnerName = firstTimeEntry.Owner.Name,
                    Date = firstTimeEntry.Date.Date,
                    Notes = r.Select(te => te.Note).ToArray(),
                    TotalTime = r.Sum(te => te.Duration)
                };
                reportItem.IsUnderPreferredWorkingHoursPerDay =
                    firstTimeEntry.Owner.PreferredWorkingHourPerDay > reportItem.TotalTime;

                return reportItem;
            })
                   .ToArray());
        }