public Task <FindResults <PersistentEvent> > GetMostRecentAsync(string projectId, DateTime utcStart, DateTime utcEnd, PagingOptions paging, bool includeHidden = false, bool includeFixed = false, bool includeNotFound = true)
        {
            var filter = new FilterContainer();

            if (!includeHidden)
            {
                filter &= !Filter <PersistentEvent> .Term(e => e.IsHidden, true);
            }

            if (!includeFixed)
            {
                filter &= !Filter <PersistentEvent> .Term(e => e.IsFixed, true);
            }

            if (!includeNotFound)
            {
                filter &= !Filter <PersistentEvent> .Term(e => e.Type, "404");
            }

            if (utcStart != DateTime.MinValue)
            {
                filter &= Filter <PersistentEvent> .Range(r => r.OnField(e => e.Date).GreaterOrEquals(utcStart));
            }
            if (utcEnd != DateTime.MaxValue)
            {
                filter &= Filter <PersistentEvent> .Range(r => r.OnField(e => e.Date).LowerOrEquals(utcEnd));
            }

            return(FindAsync(new ElasticSearchOptions <PersistentEvent>().WithProjectId(projectId).WithFilter(filter).WithIndices(utcStart, utcEnd).WithPaging(paging).WithSort(s => s.OnField(e => e.Date).Descending())));
        }
Beispiel #2
0
        public virtual ICollection <T> GetByOrganizationIds(ICollection <string> organizationIds, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (organizationIds == null || organizationIds.Count == 0)
            {
                return(new List <T>());
            }

            string cacheKey = String.Concat("org:", String.Join("", organizationIds).GetHashCode().ToString());

            return(Find(new ElasticSearchOptions <T>()
                        .WithOrganizationIds(organizationIds)
                        .WithPaging(paging)
                        .WithCacheKey(useCache ? cacheKey : null)
                        .WithExpiresIn(expiresIn)));
        }
        public Task <FindResults <PersistentEvent> > GetByOrganizationIdsAsync(ICollection <string> organizationIds, string query = null, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (organizationIds == null || organizationIds.Count == 0)
            {
                return(Task.FromResult(new FindResults <PersistentEvent>()));
            }

            string cacheKey = String.Concat("org:", String.Join("", organizationIds).GetHashCode().ToString());

            return(FindAsync(new ElasticSearchOptions <PersistentEvent>()
                             .WithOrganizationIds(organizationIds)
                             .WithQuery(query)
                             .WithPaging(GetPagingWithSortingOptions(paging))
                             .WithCacheKey(useCache ? cacheKey : null)
                             .WithExpiresIn(expiresIn)));
        }
        private ElasticSearchPagingOptions <PersistentEvent> GetPagingWithSortingOptions(PagingOptions paging)
        {
            var pagingOptions = new ElasticSearchPagingOptions <PersistentEvent>(paging);

            pagingOptions.SortBy.Add(s => s.OnField(f => f.Date).Descending());
            pagingOptions.SortBy.Add(s => s.OnField("_uid").Descending());

            return(pagingOptions);
        }
        public Task <FindResults <PersistentEvent> > GetByStackIdOccurrenceDateAsync(string stackId, DateTime utcStart, DateTime utcEnd, PagingOptions paging)
        {
            var filter = new FilterContainer();

            if (utcStart != DateTime.MinValue)
            {
                filter &= Filter <PersistentEvent> .Range(r => r.OnField(e => e.Date).GreaterOrEquals(utcStart));
            }
            if (utcEnd != DateTime.MaxValue)
            {
                filter &= Filter <PersistentEvent> .Range(r => r.OnField(e => e.Date).LowerOrEquals(utcEnd));
            }

            return(FindAsync(new ElasticSearchOptions <PersistentEvent>().WithStackId(stackId).WithFilter(filter).WithIndices(utcStart, utcEnd).WithPaging(paging).WithSort(s => s.OnField(e => e.Date).Descending())));
        }
 public override Task <FindResults <PersistentEvent> > GetByOrganizationIdAsync(string organizationId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(GetByOrganizationIdsAsync(new[] { organizationId }, paging, useCache, expiresIn));
 }
 public override Task <FindResults <PersistentEvent> > GetByProjectIdAsync(string projectId, PagingOptions paging = null)
 {
     return(FindAsync(new ExceptionlessQuery()
                      .WithProjectId(projectId)
                      .WithPaging(paging)
                      .WithSort(EventIndexType.Fields.Date, SortOrder.Descending)
                      .WithSort("_uid", SortOrder.Descending)));
 }
Beispiel #8
0
        public ICollection <Stack> GetNew(string projectId, DateTime utcStart, DateTime utcEnd, PagingOptions paging, string query)
        {
            var options = new ElasticSearchOptions <Stack>().WithProjectId(projectId).WithQuery(query).WithSort(s => s.OnField(e => e.FirstOccurrence).Descending()).WithPaging(paging);

            options.Filter = Filter <Stack> .Range(r => r.OnField(s => s.FirstOccurrence).GreaterOrEquals(utcStart));

            options.Filter &= Filter <Stack> .Range(r => r.OnField(s => s.FirstOccurrence).LowerOrEquals(utcEnd));

            return(Find(options));
        }
        // TODO: We need to index and search by the created time.
        public Task <FindResults <PersistentEvent> > GetOpenSessionsAsync(DateTime createdBeforeUtc, PagingOptions paging = null)
        {
            var filter = Filter <PersistentEvent> .Term(e => e.Type, Event.KnownTypes.Session) && Filter <PersistentEvent> .Missing(e => e.Idx[Event.KnownDataKeys.SessionEnd + "-d"]);

            if (createdBeforeUtc.Ticks > 0)
            {
                filter &= Filter <PersistentEvent> .Range(r => r.OnField(e => e.Date).LowerOrEquals(createdBeforeUtc));
            }

            return(FindAsync(new ExceptionlessQuery()
                             .WithElasticFilter(filter)
                             .WithSort(EventIndexType.Fields.Date, SortOrder.Descending)
                             .WithPaging(paging)));
        }
        public override Task <FindResults <PersistentEvent> > GetByOrganizationIdAsync(string organizationId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (String.IsNullOrEmpty(organizationId))
            {
                throw new ArgumentNullException(nameof(organizationId));
            }

            return(FindAsync(new ExceptionlessQuery()
                             .WithOrganizationId(organizationId)
                             .WithPaging(paging)
                             .WithSort(EventIndexType.Fields.Date, SortOrder.Descending)
                             .WithSort("_uid", SortOrder.Descending)
                             .WithExpiresIn(expiresIn)));
        }
        public Task <FindResults <PersistentEvent> > GetByFilterAsync(IExceptionlessSystemFilterQuery systemFilter, string userFilter, SortingOptions sorting, string field, DateTime utcStart, DateTime utcEnd, PagingOptions paging)
        {
            if (sorting.Fields.Count == 0)
            {
                sorting.Fields.Add(new FieldSort {
                    Field = EventIndexType.Fields.Date, Order = SortOrder.Descending
                });
            }

            var search = new ExceptionlessQuery()
                         .WithDateRange(utcStart, utcEnd, field ?? EventIndexType.Fields.Date)
                         .WithIndexes(utcStart, utcEnd)
                         .WithSystemFilter(systemFilter)
                         .WithFilter(userFilter)
                         .WithPaging(paging)
                         .WithSort(sorting);

            return(FindAsync(search));
        }
        public virtual Task <FindResults <User> > GetByOrganizationIdsAsync(ICollection <string> organizationIds, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (organizationIds == null || organizationIds.Count == 0)
            {
                return(Task.FromResult(new FindResults <User> {
                    Documents = new List <User>(), Total = 0
                }));
            }

            string cacheKey = String.Concat("org:", String.Join("", organizationIds).GetHashCode().ToString());
            var    filter   = Filter <User> .Term(u => u.OrganizationIds, organizationIds);

            return(FindAsync(new ElasticSearchOptions <User>()
                             .WithFilter(filter)
                             .WithPaging(paging)
                             .WithCacheKey(useCache ? cacheKey : null)
                             .WithExpiresIn(expiresIn)));
        }
 public virtual Task <FindResults <User> > GetByOrganizationIdAsync(string organizationId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(GetByOrganizationIdsAsync(new[] { organizationId }, paging, useCache, expiresIn));
 }
Beispiel #14
0
        public ICollection <Organization> GetByCriteria(string criteria, PagingOptions paging, OrganizationSortBy sortBy, bool?paid = null, bool?suspended = null)
        {
            var options = new MultiOptions().WithPaging(paging);

            if (!String.IsNullOrWhiteSpace(criteria))
            {
                options.Query = options.Query.And(Query.Matches(FieldNames.Name, new BsonRegularExpression(String.Format("/{0}/i", criteria))));
            }

            if (paid.HasValue)
            {
                if (paid.Value)
                {
                    options.Query = options.Query.And(Query.NE(FieldNames.PlanId, new BsonString(BillingManager.FreePlan.Id)));
                }
                else
                {
                    options.Query = options.Query.And(Query.EQ(FieldNames.PlanId, new BsonString(BillingManager.FreePlan.Id)));
                }
            }

            if (suspended.HasValue)
            {
                if (suspended.Value)
                {
                    options.Query = options.Query.And(
                        Query.Or(
                            Query.And(
                                Query.NE(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Active)),
                                Query.NE(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Trialing)),
                                Query.NE(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Canceled))
                                ),
                            Query.EQ(FieldNames.IsSuspended, new BsonBoolean(true))));
                }
                else
                {
                    options.Query = options.Query.And(
                        Query.Or(
                            Query.EQ(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Active)),
                            Query.EQ(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Trialing)),
                            Query.EQ(FieldNames.BillingStatus, new BsonInt32((int)BillingStatus.Canceled))
                            ),
                        Query.EQ(FieldNames.IsSuspended, new BsonBoolean(false)));
                }
            }

            switch (sortBy)
            {
            case OrganizationSortBy.Newest:
                options.SortBy = SortBy.Descending(FieldNames.Id);
                break;

            case OrganizationSortBy.Subscribed:
                options.SortBy = SortBy.Descending(FieldNames.SubscribeDate);
                break;

            case OrganizationSortBy.MostActive:
                options.SortBy = SortBy.Descending(FieldNames.TotalEventCount);
                break;

            default:
                options.SortBy = SortBy.Ascending(FieldNames.Name);
                break;
            }

            return(Find <Organization>(options));
        }
Beispiel #15
0
        public Task <FindResults <Organization> > GetByCriteriaAsync(string criteria, PagingOptions paging, OrganizationSortBy sortBy, bool?paid = null, bool?suspended = null)
        {
            var filter = Filter <Organization> .MatchAll();

            if (!String.IsNullOrWhiteSpace(criteria))
            {
                filter &= Filter <Organization> .Term(o => o.Name, criteria);
            }

            if (paid.HasValue)
            {
                if (paid.Value)
                {
                    filter &= !Filter <Organization> .Term(o => o.PlanId, BillingManager.FreePlan.Id);
                }
                else
                {
                    filter &= Filter <Organization> .Term(o => o.PlanId, BillingManager.FreePlan.Id);
                }
            }

            if (suspended.HasValue)
            {
                if (suspended.Value)
                {
                    filter &= Filter <Organization> .And(and => ((
                                                                     !Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Active) &&
                                                                     !Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Trialing) &&
                                                                     !Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Canceled)
                                                                     ) || Filter <Organization> .Term(o => o.IsSuspended, true)));
                }
                else
                {
                    filter &= Filter <Organization> .And(and => ((
                                                                     Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Active) &&
                                                                     Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Trialing) &&
                                                                     Filter <Organization> .Term(o => o.BillingStatus, BillingStatus.Canceled)
                                                                     ) || Filter <Organization> .Term(o => o.IsSuspended, false)));
                }
            }

            var query = new ExceptionlessQuery().WithPaging(paging).WithElasticFilter(filter);

            switch (sortBy)
            {
            case OrganizationSortBy.Newest:
                query.WithSort(OrganizationIndex.Fields.Organization.Id, SortOrder.Descending);
                break;

            case OrganizationSortBy.Subscribed:
                query.WithSort(OrganizationIndex.Fields.Organization.SubscribeDate, SortOrder.Descending);
                break;

            // case OrganizationSortBy.MostActive:
            //    query.WithSort(OrganizationIndex.Fields.Organization.TotalEventCount, SortOrder.Descending);
            //    break;
            default:
                query.WithSort(OrganizationIndex.Fields.Organization.Name, SortOrder.Ascending);
                break;
            }

            return(FindAsync(query));
        }
Beispiel #16
0
        public ICollection <Stack> GetByFilter(string systemFilter, string userFilter, string sort, SortOrder sortOrder, string field, DateTime utcStart, DateTime utcEnd, PagingOptions paging)
        {
            if (String.IsNullOrEmpty(sort))
            {
                sort      = "last";
                sortOrder = SortOrder.Descending;
            }

            var search = new ElasticSearchOptions <Stack>()
                         .WithDateRange(utcStart, utcEnd, field ?? "last")
                         .WithFilter(!String.IsNullOrEmpty(systemFilter) ? Filter <Stack> .Query(q => q.QueryString(qs => qs.DefaultOperator(Operator.And).Query(systemFilter))) : null)
                         .WithQuery(userFilter)
                         .WithPaging(paging)
                         .WithSort(e => e.OnField(sort).Order(sortOrder == SortOrder.Descending ? Nest.SortOrder.Descending : Nest.SortOrder.Ascending));

            return(Find(search));
        }
        public Task <FindResults <Stack> > GetByFilterAsync(string systemFilter, string userFilter, SortingOptions sorting, string field, DateTime utcStart, DateTime utcEnd, PagingOptions paging)
        {
            if (sorting.Fields.Count == 0)
            {
                sorting.Fields.Add(new FieldSort {
                    Field = StackIndex.Fields.Stack.LastOccurrence, Order = SortOrder.Descending
                });
            }

            var search = new ExceptionlessQuery()
                         .WithDateRange(utcStart, utcEnd, field ?? StackIndex.Fields.Stack.LastOccurrence)
                         .WithSystemFilter(systemFilter)
                         .WithFilter(userFilter)
                         .WithPaging(paging)
                         .WithSort(sorting);

            return(FindAsync(search));
        }
        public static ElasticSearchOptions <T> WithPaging <T>(this ElasticSearchOptions <T> options, PagingOptions paging) where T : class
        {
            if (paging == null)
            {
                return(options);
            }

            var elasticSearchPagingOptions = paging as ElasticSearchPagingOptions <T>;

            if (elasticSearchPagingOptions != null)
            {
                options.SortBy.AddRange(elasticSearchPagingOptions.SortBy);
            }

            options.Page  = paging.Page;
            options.Limit = paging.Limit;

            options.HasMore         = false;
            options.HasMoreChanged += (source, args) => paging.HasMore = args.Value;
            return(options);
        }
        public Task <FindResults <Stack> > GetNewAsync(string projectId, DateTime utcStart, DateTime utcEnd, PagingOptions paging, string filter)
        {
            var filterContainer = Filter <Stack> .Range(r => r.OnField(s => s.FirstOccurrence).GreaterOrEquals(utcStart)) && Filter <Stack> .Range(r => r.OnField(s => s.FirstOccurrence).LowerOrEquals(utcEnd));

            var query = new ExceptionlessQuery()
                        .WithProjectId(projectId)
                        .WithElasticFilter(filterContainer)
                        .WithFilter(filter)
                        .WithSort(StackIndex.Fields.Stack.FirstOccurrence, SortOrder.Descending)
                        .WithPaging(paging);

            return(FindAsync(query));
        }
 private Task <FindResults <PersistentEvent> > GetOldestEventsAsync(string stackId, PagingOptions options)
 {
     return(FindAsync(new ElasticSearchOptions <PersistentEvent>()
                      .WithStackId(stackId)
                      .WithFields("id", "organization_id", "project_id", "stack_id")
                      .WithSort(s => s.OnField(e => e.Date).Descending())
                      .WithPaging(options)));
 }
        public override Task <FindResults <Token> > GetByProjectIdAsync(string projectId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            var filter = Filter <Token> .And(and => (Filter <Token> .Term(t => t.ProjectId, projectId) || Filter <Token> .Term(t => t.DefaultProjectId, projectId)));

            return(FindAsync(new ElasticSearchOptions <Token>()
                             .WithFilter(filter)
                             .WithPaging(paging)
                             .WithCacheKey(useCache ? String.Concat("project:", projectId) : null)
                             .WithExpiresIn(expiresIn)));
        }
 public override Task <FindResults <PersistentEvent> > GetByOrganizationIdsAsync(ICollection <string> organizationIds, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(base.GetByOrganizationIdsAsync(organizationIds, GetPagingWithSortingOptions(paging), useCache, expiresIn));
 }
 public Task <FindResults <Token> > GetByTypeAndOrganizationIdAsync(TokenType type, string organizationId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(FindAsync(new ElasticSearchOptions <Token>()
                      .WithOrganizationId(organizationId)
                      .WithFilter(Filter <Token> .Term(t => t.Type, type))
                      .WithPaging(paging)
                      .WithCacheKey(useCache ? String.Concat("type:", type, "-org:", organizationId) : null)
                      .WithExpiresIn(expiresIn)));
 }
 public override Task <FindResults <PersistentEvent> > GetByProjectIdAsync(string projectId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(base.GetByProjectIdAsync(projectId, GetPagingWithSortingOptions(paging), useCache, expiresIn));
 }
        public Task <FindResults <Token> > GetByTypeAndOrganizationIdsAsync(TokenType type, ICollection <string> organizationIds, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (organizationIds == null || organizationIds.Count == 0)
            {
                return(Task.FromResult(new FindResults <Token>()));
            }

            string cacheKey = String.Concat("type:", type, "-org:", String.Join("", organizationIds).GetHashCode().ToString());

            return(FindAsync(new ElasticSearchOptions <Token>()
                             .WithOrganizationIds(organizationIds)
                             .WithFilter(Filter <Token> .Term(t => t.Type, type))
                             .WithPaging(paging)
                             .WithCacheKey(useCache ? cacheKey : null)
                             .WithExpiresIn(expiresIn)));
        }
        public Task <FindResults <PersistentEvent> > GetByFilterAsync(string systemFilter, string userFilter, string sort, SortOrder sortOrder, string field, DateTime utcStart, DateTime utcEnd, PagingOptions paging)
        {
            if (String.IsNullOrEmpty(sort))
            {
                sort      = "date";
                sortOrder = SortOrder.Descending;
            }

            var search = new ElasticSearchOptions <PersistentEvent>()
                         .WithDateRange(utcStart, utcEnd, field ?? "date")
                         .WithIndicesFromDateRange($"'{_index.VersionedName}-'yyyyMM")
                         .WithFilter(!String.IsNullOrEmpty(systemFilter) ? Filter <PersistentEvent> .Query(q => q.QueryString(qs => qs.DefaultOperator(Operator.And).Query(systemFilter))) : null)
                         .WithQuery(userFilter)
                         .WithPaging(paging)
                         .WithSort(e => e.OnField(sort).Order(sortOrder == SortOrder.Descending ? Nest.SortOrder.Descending : Nest.SortOrder.Ascending));

            return(FindAsync(search));
        }
        public Task <FindResults <Token> > GetByTypeAndOrganizationIdOrProjectIdAsync(TokenType type, string organizationId, string projectId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            var filter = Filter <Token> .And(and => (
                                                 Filter <Token> .Term(t => t.OrganizationId, organizationId) || Filter <Token> .Term(t => t.ProjectId, projectId) || Filter <Token> .Term(t => t.DefaultProjectId, projectId)
                                                 ) && Filter <Token> .Term(t => t.Type, type));

            return(FindAsync(new ElasticSearchOptions <Token>()
                             .WithFilter(filter)
                             .WithPaging(paging)
                             .WithCacheKey(String.Concat("type:", type, "-org:", organizationId, "-project:", projectId))
                             .WithExpiresIn(expiresIn)));
        }
Beispiel #28
0
 public virtual ICollection <T> GetByOrganizationId(string organizationId, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
 {
     return(GetByOrganizationIds(new[] { organizationId }, paging, useCache, expiresIn));
 }
Beispiel #29
0
        public ICollection <Stack> GetNew(string projectId, DateTime utcStart, DateTime utcEnd, PagingOptions paging, bool includeHidden = false, bool includeFixed = false, bool includeNotFound = true)
        {
            var options = new MultiOptions().WithProjectId(projectId).WithSort(SortBy.Descending(FieldNames.FirstOccurrence)).WithPaging(paging);

            options.Query = options.Query.And(Query.GTE(FieldNames.FirstOccurrence, utcStart), Query.LTE(FieldNames.FirstOccurrence, utcEnd));

            if (!includeFixed)
            {
                options.Query = options.Query.And(Query.NotExists(FieldNames.DateFixed));
            }

            if (!includeHidden)
            {
                options.Query = options.Query.And(Query.NE(FieldNames.IsHidden, true));
            }

            if (!includeNotFound)
            {
                options.Query = options.Query.And(Query.NotExists(FieldNames.SignatureInfo_Path));
            }

            return(Find <Stack>(options));
        }
        public ICollection <T> GetByIds(ICollection <string> ids, PagingOptions paging = null, bool useCache = false, TimeSpan?expiresIn = null)
        {
            if (ids == null || ids.Count == 0)
            {
                return(new List <T>());
            }

            var results = new List <T>();

            if (EnableCache && useCache)
            {
                results.AddRange(ids.Select(id => Cache.Get <T>(GetScopedCacheKey(id))).Where(cacheHit => cacheHit != null));

                var notCachedIds = ids.Except(results.Select(i => i.Id)).ToArray();
                if (notCachedIds.Length == 0)
                {
                    return(results);
                }
            }

            // try using the object id to figure out what index the entity is located in
            var foundItems  = new List <T>();
            var itemsToFind = new List <string>();
            var multiGet    = new MultiGetDescriptor();

            foreach (var id in ids.Except(results.Select(i => i.Id)))
            {
                string index = GetIndexName(id);
                if (index != null)
                {
                    multiGet.Get <T>(f => f.Id(id).Index(index).Source(s => s.Exclude("idx")));
                }
                else
                {
                    itemsToFind.Add(id);
                }
            }

            _elasticClient.EnableTrace();
            foreach (var doc in _elasticClient.MultiGet(multiGet).Documents)
            {
                if (doc.Found)
                {
                    foundItems.Add(doc.Source as T);
                }
                else
                {
                    itemsToFind.Add(doc.Id);
                }
            }
            _elasticClient.DisableTrace();

            // fallback to doing a find
            if (itemsToFind.Count > 0)
            {
                foundItems.AddRange(Find(new ElasticSearchOptions <T>().WithIds(itemsToFind)));
            }

            if (EnableCache && useCache && foundItems.Count > 0)
            {
                foreach (var item in foundItems)
                {
                    Cache.Set(GetScopedCacheKey(item.Id), item, expiresIn.HasValue ? DateTime.Now.Add(expiresIn.Value) : DateTime.Now.AddSeconds(RepositoryConstants.DEFAULT_CACHE_EXPIRATION_SECONDS));
                }
            }

            results.AddRange(foundItems);
            return(results);
        }
        private async Task ProcessSummaryNotificationAsync(SummaryNotification data) {
            var project = await _projectRepository.GetByIdAsync(data.Id, true).AnyContext();
            var organization = await _organizationRepository.GetByIdAsync(project.OrganizationId, true).AnyContext();
            var userIds = project.NotificationSettings.Where(n => n.Value.SendDailySummary).Select(n => n.Key).ToList();
            if (userIds.Count == 0) {
                Log.Info().Message("Project \"{0}\" has no users to send summary to.", project.Id).Write();
                return;
            }

            var users = (await _userRepository.GetByIdsAsync(userIds).AnyContext()).Documents.Where(u => u.IsEmailAddressVerified && u.EmailNotificationsEnabled && u.OrganizationIds.Contains(organization.Id)).ToList();
            if (users.Count == 0) {
                Log.Info().Message("Project \"{0}\" has no users to send summary to.", project.Id).Write();
                return;
            }

            Log.Info().Message("Sending daily summary: users={0} project={1}", users.Count, project.Id).Write();
            var paging = new PagingOptions { Limit = 5 };
            List<Stack> newest = (await _stackRepository.GetNewAsync(project.Id, data.UtcStartTime, data.UtcEndTime, paging).AnyContext()).Documents.ToList();

            var result = await _stats.GetTermsStatsAsync(data.UtcStartTime, data.UtcEndTime, "stack_id", "type:error project:" + data.Id, max: 5).AnyContext();
            //var termStatsList = result.Terms.Take(5).ToList();
            //var stacks = _stackRepository.GetByIds(termStatsList.Select(s => s.Term).ToList());
            bool hasSubmittedErrors = result.Total > 0;
            if (!hasSubmittedErrors)
                hasSubmittedErrors = await _eventRepository.GetCountByProjectIdAsync(project.Id).AnyContext() > 0;

            var mostFrequent = new List<EventStackResult>();
            //foreach (var termStats in termStatsList) {
            //    var stack = stacks.SingleOrDefault(s => s.Id == termStats.Term);
            //    if (stack == null)
            //        continue;

            //    mostFrequent.Add(new EventStackResult {
            //        First =  termStats.FirstOccurrence,
            //        Last = termStats.LastOccurrence,
            //        Id = stack.Id,
            //        Title = stack.Title,
            //        Total = termStats.Total,
            //        Type = stack.SignatureInfo.ContainsKey("ExceptionType") ? stack.SignatureInfo["ExceptionType"] : null,
            //        Method = stack.SignatureInfo.ContainsKey("Method") ? stack.SignatureInfo["Method"] : null,
            //        Path = stack.SignatureInfo.ContainsKey("Source") ? stack.SignatureInfo["Source"] : null,
            //        Is404 = stack.SignatureInfo.ContainsKey("Type") && stack.SignatureInfo["Type"] == "404"
            //    });
            //}

            var notification = new DailySummaryModel {
                ProjectId = project.Id,
                ProjectName = project.Name,
                StartDate = data.UtcStartTime,
                EndDate = data.UtcEndTime,
                Total = result.Total,
                PerHourAverage = result.Total / data.UtcEndTime.Subtract(data.UtcStartTime).TotalHours,
                NewTotal = result.New,
                New = newest,
                UniqueTotal = result.Unique,
                MostFrequent = mostFrequent,
                HasSubmittedEvents = hasSubmittedErrors,
                IsFreePlan = organization.PlanId == BillingManager.FreePlan.Id
            };

            foreach (var user in users)
                await _mailer.SendDailySummaryAsync(user.EmailAddress, notification).AnyContext();
            
            Log.Info().Message("Done sending daily summary: users={0} project={1} events={2}", users.Count, project.Id, notification.Total).Write();
        }