public DailySummaryHierarchy(ActivityGroupHierarchy activityGroupHierarchy, int numDays)
        {
            _activityGroupHierarchy = activityGroupHierarchy;
            _numDays = numDays;

            BuildSummaryHierarchy();
        }
Esempio n. 2
0
        public async Task <TotalsReply> Get([FromQuery] string groupBy, [FromQuery] DateTime from, [FromQuery] DateTime to)
        {
            // Basic validation.
            if (to < from)
            {
                throw new BadRequestException("'from' parameter cannot be after 'to'.");
            }

            // Select the right grouping period structure.
            // We'll strip off the time zone information to avoid any issues.
            var cleanedFrom = DateTime.SpecifyKind(from, DateTimeKind.Unspecified);
            var cleanedTo   = DateTime.SpecifyKind(to, DateTimeKind.Unspecified);

            PeriodStructureBase periodStructure;

            if (groupBy == Day)
            {
                periodStructure = new DailyPeriodStructure(cleanedFrom, cleanedTo);
            }
            else if (groupBy == Week)
            {
                periodStructure = new WeeklyPeriodStructure(cleanedFrom, cleanedTo);
            }
            else if (groupBy == Month)
            {
                periodStructure = new MonthlyPeriodStructure(cleanedFrom, cleanedTo);
            }
            else if (groupBy == Custom)
            {
                periodStructure = new CustomPeriodStructure(cleanedFrom, cleanedTo);
            }
            else if (string.IsNullOrEmpty(groupBy))
            {
                throw new BadRequestException("Must provide a valid 'groupBy' field.");
            }
            else
            {
                throw new BadRequestException($"Unsupported 'groupBy' value: '{groupBy}'");
            }

            // Load the responses in the specified time range.
            var fromTime = periodStructure.FromTime;
            var toTime   = periodStructure.ToTime;
            var numDays  = (int)Math.Round((toTime - fromTime).TotalDays);

            if (numDays > MaxAllowedDaysInRange)
            {
                throw new BadRequestException($"The requested date range cannot have more than {MaxAllowedDaysInRange} days.");
            }

            // Load the responses for that time range.
            var poll = await GetDefaultPollAsync();

            var timeLogEntries = await _timeLogService.Get(Db, poll.Id, fromTime, toTime);

            // Trim the ends to make sure that we count only the time from the first and last entry that fits
            // into the range.
            if (timeLogEntries.Count > 0)
            {
                var lastEntry = timeLogEntries[timeLogEntries.Count - 1];

                if (lastEntry.FromTime < fromTime)
                {
                    lastEntry.TimeBlockLength = lastEntry.TimeBlockLength - (fromTime - lastEntry.FromTime);
                    lastEntry.FromTime        = fromTime;
                }

                var firstEntry = timeLogEntries[0];

                if (firstEntry.GetToTime() > toTime)
                {
                    firstEntry.TimeBlockLength = firstEntry.TimeBlockLength - (firstEntry.GetToTime() - toTime);
                }
            }

            // Load the user's ActivityGroup hierarchy.
            var activityGroups = await Db.ActivityGroups.Where(g => g.PollId == poll.Id).ToListAsync();

            var activityHierarchy = new ActivityGroupHierarchy(activityGroups, _loggerFactory);

            // Prepare for calculation.
            var totalsReply = new TotalsReply();

            totalsReply.StartingDates = periodStructure.GetPeriodStartDates();
            var summariesByActivity = new Dictionary <string, TotalsForActivity>();

            // Initial pass - find all activities.
            var totalsHierarchy = new TotalsHierarchy(activityHierarchy, periodStructure.NumPeriods);

            foreach (var timeLogEntry in timeLogEntries)
            {
                int dateIndex = -2;

                try
                {
                    var summaryForActivity = totalsHierarchy.GetOrAddActivity(timeLogEntry.EntryText);
                    dateIndex = periodStructure.CalcEntryPeriodIndex(timeLogEntry.FromTime);

                    summaryForActivity.TimeSpentPerPeriod[dateIndex] =
                        summaryForActivity.TimeSpentPerPeriod[dateIndex] + timeLogEntry.TimeBlockLength;
                }
                catch (ArgumentOutOfRangeException ex)
                {
                    throw new Exception($"Totals IndexOutOfRangeException. Account: {Account.Id}; dateIndex: {dateIndex}", ex);
                }
            }


            // Additional passes - aggregate and clean up the data.
            totalsHierarchy.RecalculateTimeTotals();
            totalsHierarchy.PruneEmptyLeafs();

            // Compose the response.
            totalsReply.Activities = totalsHierarchy.GetActivities();

            return(totalsReply);
        }
        public async Task <DailySummaryReply> Get([FromQuery] DateTime from, [FromQuery] DateTime to)
        {
            // Basic validation.
            if (to < from)
            {
                throw new BadRequestException("'from' parameter cannot be after 'to'.");
            }

            // Load the responses in the specified time range.
            // We'll strip off the time zone information to avoid any issues.
            var fromDate = DateTime.SpecifyKind(from.Date, DateTimeKind.Unspecified);
            var toDate   = DateTime.SpecifyKind(to.Date.AddDays(1), DateTimeKind.Unspecified); // +1 day because we process responses until the END of toDate.
            var numDays  = (int)Math.Round((toDate - fromDate).TotalDays);

            if (numDays > MaxAllowedDaysInRange)
            {
                throw new BadRequestException($"The requested date range cannot have more than {MaxAllowedDaysInRange} days.");
            }

            // Load the responses for that time range.
            var poll = await GetDefaultPollAsync();

            var timeLogEntries = await _timeLogService.Get(Db, poll.Id, fromDate, toDate);

            // Trim the ends to make sure that we count only the time from the first and last entry that fits
            // into the range.
            if (timeLogEntries.Count > 0)
            {
                var firstEntry = timeLogEntries[0];

                if (firstEntry.FromTime < fromDate)
                {
                    firstEntry.TimeBlockLength = firstEntry.TimeBlockLength - (fromDate - firstEntry.FromTime);
                    firstEntry.FromTime        = fromDate;
                }

                var lastEntry = timeLogEntries[timeLogEntries.Count - 1];

                if (lastEntry.GetToTime() > toDate)
                {
                    lastEntry.TimeBlockLength = lastEntry.TimeBlockLength - (lastEntry.GetToTime() - toDate);
                }
            }

            // Load the user's ActivityGroup hierarchy.
            var activityGroups = await Db.ActivityGroups.Where(g => g.PollId == poll.Id).ToListAsync();

            var activityHierarchy = new ActivityGroupHierarchy(activityGroups, _loggerFactory);

            // Prepare for calculation.
            var dailySummary = new DailySummaryReply();

            dailySummary.Dates = GenerateDates(fromDate, numDays);
            var summariesByActivity = new Dictionary <string, DailySummaryForActivity>();

            // Initial pass - find all activities.
            var dailySummaryHierarchy = new DailySummaryHierarchy(activityHierarchy, numDays);

            foreach (var timeLogEntry in timeLogEntries)
            {
                var summaryForActivity = dailySummaryHierarchy.GetOrAddActivity(timeLogEntry.EntryText);
                var dateIndex          = CalcDateIndex(timeLogEntry.FromTime, fromDate);
                summaryForActivity.TimeSpentPerDay[dateIndex] =
                    summaryForActivity.TimeSpentPerDay[dateIndex] + timeLogEntry.TimeBlockLength;
            }

            // Additional passes - aggregate and clean up the data.
            dailySummaryHierarchy.RecalculateTimeTotals();
            dailySummaryHierarchy.PruneEmptyLeafs();

            // Compose the response.
            dailySummary.Activities = dailySummaryHierarchy.GetActivities();

            return(dailySummary);
        }