public async Task CanGetByFixedAsync() { var stack = await _repository.AddAsync(StackData.GenerateStack(id: TestConstants.StackId, projectId: TestConstants.ProjectId, organizationId: TestConstants.OrganizationId)); await RefreshDataAsync(); var results = await _repository.GetByFilterAsync(null, "fixed:true", null, null, DateTime.MinValue, DateTime.MaxValue); Assert.NotNull(results); Assert.Equal(0, results.Total); results = await _repository.GetByFilterAsync(null, "fixed:false", null, null, DateTime.MinValue, DateTime.MaxValue); Assert.NotNull(results); Assert.Equal(1, results.Total); Assert.False(results.Documents.Single().IsRegressed); Assert.Null(results.Documents.Single().DateFixed); stack.MarkFixed(); await _repository.SaveAsync(stack); await RefreshDataAsync(); results = await _repository.GetByFilterAsync(null, "fixed:true", null, null, DateTime.MinValue, DateTime.MaxValue); Assert.NotNull(results); Assert.Equal(1, results.Total); Assert.False(results.Documents.Single().IsRegressed); Assert.NotNull(results.Documents.Single().DateFixed); results = await _repository.GetByFilterAsync(null, "fixed:false", null, null, DateTime.MinValue, DateTime.MaxValue); Assert.NotNull(results); Assert.Equal(0, results.Total); }
private Task <FindResults <Stack> > GetByFilterAsync(string filter) { return(_repository.GetByFilterAsync(null, filter, new SortingOptions(), null, DateTime.MinValue, DateTime.MaxValue, new PagingOptions())); }
private async Task <bool> SendSummaryNotificationAsync(Project project, SummaryNotification data) { // TODO: Add slack daily summaries var userIds = project.NotificationSettings.Where(n => n.Value.SendDailySummary && !String.Equals(n.Key, Project.NotificationIntegrations.Slack)).Select(n => n.Key).ToList(); if (userIds.Count == 0) { _logger.LogInformation("Project {ProjectName} has no users to send summary to.", project.Name); return(false); } var results = await _userRepository.GetByIdsAsync(userIds, o => o.Cache()).AnyContext(); var users = results.Where(u => u.IsEmailAddressVerified && u.EmailNotificationsEnabled && u.OrganizationIds.Contains(project.OrganizationId)).ToList(); if (users.Count == 0) { _logger.LogInformation("Project {ProjectName} has no users to send summary to.", project.Name); return(false); } // TODO: What should we do about suspended organizations. var organization = await _organizationRepository.GetByIdAsync(project.OrganizationId, o => o.Cache()).AnyContext(); if (organization == null) { _logger.LogInformation("The organization {organization} for project {ProjectName} may have been deleted. No summaries will be sent.", project.OrganizationId, project.Name); return(false); } _logger.LogInformation("Sending daily summary: users={UserCount} project={project}", users.Count, project.Id); var sf = new ExceptionlessSystemFilter(project, organization); var systemFilter = new RepositoryQuery <PersistentEvent>().SystemFilter(sf).DateRange(data.UtcStartTime, data.UtcEndTime, (PersistentEvent e) => e.Date).Index(data.UtcStartTime, data.UtcEndTime); string filter = $"{EventIndexType.Alias.Type}:{Event.KnownTypes.Error} {EventIndexType.Alias.IsHidden}:false {EventIndexType.Alias.IsFixed}:false"; var result = await _eventRepository.CountBySearchAsync(systemFilter, filter, "terms:(first @include:true) terms:(stack_id~3) cardinality:stack_id sum:count~1").AnyContext(); double total = result.Aggregations.Sum("sum_count")?.Value ?? result.Total; double newTotal = result.Aggregations.Terms <double>("terms_first")?.Buckets.FirstOrDefault()?.Total ?? 0; double uniqueTotal = result.Aggregations.Cardinality("cardinality_stack_id")?.Value ?? 0; bool hasSubmittedEvents = total > 0 || project.IsConfigured.GetValueOrDefault(); bool isFreePlan = organization.PlanId == _plans.FreePlan.Id; string fixedFilter = $"{EventIndexType.Alias.Type}:{Event.KnownTypes.Error} {EventIndexType.Alias.IsHidden}:false {EventIndexType.Alias.IsFixed}:true"; var fixedResult = await _eventRepository.CountBySearchAsync(systemFilter, fixedFilter, "sum:count~1").AnyContext(); double fixedTotal = fixedResult.Aggregations.Sum("sum_count")?.Value ?? fixedResult.Total; var range = new DateTimeRange(data.UtcStartTime, data.UtcEndTime); var usages = project.OverageHours.Where(u => range.Contains(u.Date)).ToList(); int blockedTotal = usages.Sum(u => u.Blocked); int tooBigTotal = usages.Sum(u => u.TooBig); IReadOnlyCollection <Stack> mostFrequent = null; var stackTerms = result.Aggregations.Terms <string>("terms_stack_id"); if (stackTerms?.Buckets.Count > 0) { mostFrequent = await _stackRepository.GetByIdsAsync(stackTerms.Buckets.Select(b => b.Key).ToArray()).AnyContext(); } IReadOnlyCollection <Stack> newest = null; if (newTotal > 0) { newest = (await _stackRepository.GetByFilterAsync(sf, filter, "-first", "first", data.UtcStartTime, data.UtcEndTime, o => o.PageLimit(3)).AnyContext()).Documents; } foreach (var user in users) { _logger.LogInformation("Queuing {ProjectName} daily summary email ({UtcStartTime}-{UtcEndTime}) for user {EmailAddress}.", project.Name, data.UtcStartTime, data.UtcEndTime, user.EmailAddress); await _mailer.SendProjectDailySummaryAsync(user, project, mostFrequent, newest, data.UtcStartTime, hasSubmittedEvents, total, uniqueTotal, newTotal, fixedTotal, blockedTotal, tooBigTotal, isFreePlan).AnyContext(); } _logger.LogInformation("Done sending daily summary: users={UserCount} project={ProjectName} events={EventCount}", users.Count, project.Name, total); return(true); }
private Task <FindResults <Stack> > GetByFilterAsync(string filter) { return(_repository.GetByFilterAsync(null, filter, null, null, DateTime.MinValue, DateTime.MaxValue)); }
private Task <FindResults <Stack> > GetByFilterAsync(string filter) { return(_repository.GetByFilterAsync(null, filter, null, Foundatio.Repositories.Models.SortOrder.Descending, null, DateTime.MinValue, DateTime.MaxValue, new PagingOptions())); }