Пример #1
0
        /// <summary>
        /// Helper method to register the entity commands.
        /// </summary>
        public static void RegisterEntityCommands(ILavaEngine engine)
        {
            var entityTypes = EntityTypeCache.All();

            // register a business entity
            engine.RegisterBlock("business", (name) => { return(new RockEntityBlock()); });

            // Register the core models, replacing existing blocks of the same name if necessary.
            foreach (var entityType in entityTypes
                     .Where(e =>
                            e.IsEntity &&
                            e.Name.StartsWith("Rock.Model") &&
                            e.FriendlyName != null &&
                            e.FriendlyName != ""))
            {
                RegisterEntityCommand(engine, entityType, useQualifiedNameIfExists: true);
            }

            // Register plugin models, using fully-qualified namespace if necessary.
            foreach (var entityType in entityTypes
                     .Where(e =>
                            e.IsEntity &&
                            !e.Name.StartsWith("Rock.Model") &&
                            e.FriendlyName != null &&
                            e.FriendlyName != "")
                     .OrderBy(e => e.Id))
            {
                RegisterEntityCommand(engine, entityType, useQualifiedNameIfExists: true);
            }
        }
Пример #2
0
        /// <summary>
        /// Shows the settings.
        /// </summary>
        protected override void ShowSettings()
        {
            pnlEditModal.Visible = true;
            upnlContent.Update();
            mdEdit.Show();

            cblLavaCommands.Items.Clear();
            cblLavaCommands.Items.Add("All");

            // load the lava commands control
            foreach (var command in Rock.Lava.LavaHelper.GetLavaCommands())
            {
                cblLavaCommands.Items.Add(command);
            }

            List <string> selectedCommands = new List <string>();

            if (GetAttributeValue(AttributeKey.CustomResultsCommands) != null)
            {
                selectedCommands = GetAttributeValue(AttributeKey.CustomResultsCommands).Split(',').ToList();
            }

            foreach (var command in selectedCommands)
            {
                var item = cblLavaCommands.Items.FindByText(command);
                if (item != null)
                {
                    item.Selected = true;
                }
            }

            cbShowFilter.Checked = GetAttributeValue(AttributeKey.ShowFilters).AsBoolean();

            var enabledModelIds = new List <int>();

            if (GetAttributeValue(AttributeKey.EnabledModels).IsNotNullOrWhiteSpace())
            {
                enabledModelIds = GetAttributeValue(AttributeKey.EnabledModels).Split(',').Select(int.Parse).ToList();
            }

            var entities          = EntityTypeCache.All();
            var indexableEntities = entities.Where(i => i.IsIndexingSupported == true && enabledModelIds.Contains(i.Id)).ToList();

            cblEnabledModels.DataValueField = "Id";
            cblEnabledModels.DataTextField  = "FriendlyName";
            cblEnabledModels.DataSource     = entities.Where(i => i.IsIndexingSupported == true && i.IsIndexingEnabled == true).ToList();
            cblEnabledModels.DataBind();
            cblEnabledModels.SetValues(enabledModelIds);

            cbShowRefinedSearch.Checked  = GetAttributeValue(AttributeKey.ShowRefinedSearch).AsBoolean();
            cbShowScores.Checked         = GetAttributeValue(AttributeKey.ShowScores).AsBoolean();
            cbUseCustomResults.Checked   = GetAttributeValue(AttributeKey.UseCustomResults).AsBoolean();
            ceCustomResultsTemplate.Text = GetAttributeValue(AttributeKey.LavaResultTemplate);
            cePreHtml.Text          = GetAttributeValue(AttributeKey.PreHtml);
            cePostHtml.Text         = GetAttributeValue(AttributeKey.PostHtml);
            tbBaseFieldFilters.Text = GetAttributeValue(AttributeKey.BaseFieldFilters);
            tbResultsPerPage.Text   = GetAttributeValue(AttributeKey.ResultsPerPage);

            upnlContent.Update();
        }
Пример #3
0
        /// <summary>
        /// Helper method to register the entity commands.
        /// </summary>
        public static void RegisterEntityCommands()
        {
            var entityTypes = EntityTypeCache.All();

            // register a business entity
            Template.RegisterTag <RockEntity>("business");

            // Register the core models first
            foreach (var entityType in entityTypes
                     .Where(e =>
                            e.IsEntity &&
                            e.Name.StartsWith("Rock.Model") &&
                            e.FriendlyName != null &&
                            e.FriendlyName != ""))
            {
                RegisterEntityCommand(entityType);
            }

            // Now register plugin models
            foreach (var entityType in entityTypes
                     .Where(e =>
                            e.IsEntity &&
                            !e.Name.StartsWith("Rock.Model") &&
                            e.FriendlyName != null &&
                            e.FriendlyName != "")
                     .OrderBy(e => e.Id))
            {
                RegisterEntityCommand(entityType);
            }
        }
Пример #4
0
        /// <summary>
        /// Formats the search result.
        /// </summary>
        /// <param name="person">The person.</param>
        /// <param name="displayOptions">The display options.</param>
        /// <param name="mergeFields">The merge fields.</param>
        /// <returns></returns>
        public virtual FormattedSearchResult FormatSearchResult(Person person, Dictionary <string, object> displayOptions = null, Dictionary <string, object> mergeFields = null)
        {
            string result = string.Empty;

            // get template from entity type
            var sourceModelEntity = EntityTypeCache.All().Where(e => e.Name == this.SourceIndexModel).FirstOrDefault();

            if (sourceModelEntity != null)
            {
                var template = sourceModelEntity.IndexResultTemplate;

                if (template.IsNotNullOrWhiteSpace())
                {
                    if (mergeFields == null)
                    {
                        mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, person);
                    }

                    mergeFields.AddOrReplace("IndexDocument", this);
                    mergeFields.AddOrReplace("DisplayOptions", displayOptions);

                    return(new FormattedSearchResult()
                    {
                        IsViewAllowed = true, FormattedResult = template.ResolveMergeFields(mergeFields)
                    });
                }
            }

            // otherwise return not implemented (blank)
            return(new FormattedSearchResult()
            {
                IsViewAllowed = true, FormattedResult = result
            });
        }
Пример #5
0
        /// <summary>
        /// Loads the custom filters.
        /// </summary>
        private void LoadCustomFilters()
        {
            var enabledModelIds = new List <int>();

            if (GetAttributeValue(AttributeKey.EnabledModels).IsNotNullOrWhiteSpace())
            {
                enabledModelIds = GetAttributeValue(AttributeKey.EnabledModels).Split(',').Select(int.Parse).ToList();
            }

            var entities          = EntityTypeCache.All();
            var indexableEntities = entities.Where(i => i.IsIndexingEnabled == true).ToList();

            // if select entities are configured further filter by them
            if (enabledModelIds.Count > 0)
            {
                indexableEntities = indexableEntities.Where(i => enabledModelIds.Contains(i.Id)).ToList();
            }

            foreach (var entity in indexableEntities)
            {
                var entityType = entity.GetEntityType();

                if (SupportsIndexFieldFiltering(entityType))
                {
                    var filterOptions = GetIndexFilterConfig(entityType);

                    RockCheckBoxList filterConfig = new RockCheckBoxList();
                    filterConfig.Label           = filterOptions.FilterLabel;
                    filterConfig.CssClass        = "js-entity-id-" + entity.Id.ToString();
                    filterConfig.CssClass       += " js-entity-filter-field";
                    filterConfig.RepeatDirection = RepeatDirection.Horizontal;
                    filterConfig.Attributes.Add("entity-id", entity.Id.ToString());
                    filterConfig.Attributes.Add("entity-filter-field", filterOptions.FilterField);
                    filterConfig.DataSource = filterOptions.FilterValues.Where(i => i != null);
                    filterConfig.DataBind();

                    // set any selected values from the query string
                    if (!string.IsNullOrWhiteSpace(PageParameter(filterOptions.FilterField)))
                    {
                        List <string> selectedValues = PageParameter(filterOptions.FilterField).Split(',').ToList();

                        foreach (ListItem item in filterConfig.Items)
                        {
                            if (selectedValues.Contains(item.Value))
                            {
                                item.Selected = true;
                            }
                        }
                    }

                    if (filterOptions.FilterValues.Count > 0)
                    {
                        HtmlGenericContainer filterWrapper = new HtmlGenericContainer("div", "col-md-6");
                        filterWrapper.Controls.Add(filterConfig);
                        phFilters.Controls.Add(filterWrapper);
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Adds the context entities from headers.
        /// </summary>
        protected virtual void AddContextEntitiesFromHeaders()
        {
            foreach (var kvp in Headers)
            {
                //
                // Skip any header that isn't an entity context header.
                //
                if (!kvp.Key.StartsWith("X-ENTITYCONTEXT-", StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }

                //
                // Determine the the entity type in question.
                //
                var entityName = kvp.Key.Substring(16);
                var type       = EntityTypeCache.All()
                                 .Where(a => a.IsEntity)
                                 .FirstOrDefault(a => a.FriendlyName.Equals(entityName, StringComparison.InvariantCultureIgnoreCase))
                                 ?.GetEntityType();
                string entityKey = kvp.Value.First();

                //
                // If we got an unknown type or no Id/Guid then skip.
                //
                if (type == null || entityKey.IsNullOrWhiteSpace())
                {
                    continue;
                }

                //
                // Lazy load the entity so we don't actually load if it is never
                // accessed.
                //
                ContextEntities.AddOrReplace(type, new Lazy <IEntity>(() =>
                {
                    IEntity entity = null;

                    if (int.TryParse(entityKey, out int entityId))
                    {
                        entity = Reflection.GetIEntityForEntityType(type, entityId);
                    }
                    else if (Guid.TryParse(entityKey, out Guid entityGuid))
                    {
                        entity = Reflection.GetIEntityForEntityType(type, entityGuid);
                    }

                    if (entity != null && entity is IHasAttributes attributedEntity)
                    {
                        Helper.LoadAttributes(attributedEntity);
                    }

                    return(entity);
                }));
            }
        }
Пример #7
0
        /// <summary>
        /// Re-indexes the selected entity types in Universal Search
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            string     selectedEntitiesSetting = dataMap.GetString("EntityFilter");
            bool       allEntities             = dataMap.GetBoolean("IndexAllEntities");

            RockContext rockContext = new RockContext();

            var selectedEntityTypes = EntityTypeCache.All().Where(e => e.IsIndexingSupported && e.IsIndexingEnabled && e.FriendlyName != "Site");

            // if 'All' wasn't selected the filter out the ones that weren't selected
            if (!allEntities)
            {
                if (selectedEntitiesSetting.IsNotNullOrWhiteSpace())
                {
                    var selectedEntityIds = selectedEntitiesSetting.Split(',').Select(int.Parse).ToList();
                    selectedEntityTypes = selectedEntityTypes.Where(e => selectedEntityIds.Contains(e.Id));
                }
            }

            string results    = string.Empty;
            var    timerTotal = System.Diagnostics.Stopwatch.StartNew();

            foreach (var entityTypeCache in selectedEntityTypes)
            {
                EntityTypeService entityTypeService = new EntityTypeService(rockContext);
                var entityType = entityTypeService.Get(entityTypeCache.Id);

                IndexContainer.DeleteIndex(entityType.IndexModelType);
                IndexContainer.CreateIndex(entityType.IndexModelType);

                Type type = entityTypeCache.GetEntityType();

                if (type != null)
                {
                    object     classInstance   = Activator.CreateInstance(type, null);
                    MethodInfo bulkItemsMethod = type.GetMethod("BulkIndexDocuments");

                    if (classInstance != null && bulkItemsMethod != null)
                    {
                        var timer = System.Diagnostics.Stopwatch.StartNew();
                        bulkItemsMethod.Invoke(classInstance, null);
                        timer.Stop();
                        results += $"{entityType.FriendlyName}: {timer.ElapsedMilliseconds/1000}s,";
                    }
                }
            }

            results       += $"Total Time: {timerTotal.ElapsedMilliseconds / 1000}s,";
            context.Result = "Indexing results: " + results.Trim(',');
        }
Пример #8
0
        private void LoadCategories()
        {
            var entityCategories = new List <MCategory>();

            var categoryIcons      = new Dictionary <string, string>();
            var categoryIconValues = GetAttributeValue("CategoryIcons");

            if (!string.IsNullOrWhiteSpace(categoryIconValues))
            {
                categoryIconValues = categoryIconValues.TrimEnd('|');
                foreach (var keyVal in categoryIconValues.Split('|')
                         .Select(s => s.Split('^'))
                         .Where(s => s.Length == 2))
                {
                    categoryIcons.AddOrIgnore(keyVal[0], keyVal[1]);
                }
            }

            foreach (var entity in EntityTypeCache.All().Where(t => t.IsEntity))
            {
                var type = entity.GetEntityType();
                if (type != null && type.InheritsOrImplements(typeof(Rock.Data.Entity <>)))
                {
                    string category   = "Other";
                    var    domainAttr = type.GetCustomAttribute <RockDomainAttribute>(false);
                    if (domainAttr != null && domainAttr.Name.IsNotNullOrWhitespace())
                    {
                        category = domainAttr.Name;
                    }

                    var entityCategory = entityCategories
                                         .Where(c => c.Name == category)
                                         .FirstOrDefault();
                    if (entityCategory == null)
                    {
                        entityCategory = new MCategory {
                            Guid = Guid.NewGuid(), Name = category, RockEntities = new List <MEntity>()
                        };
                        entityCategory.IconCssClass = categoryIcons.ContainsKey(category) ? categoryIcons[category] : string.Empty;
                        entityCategories.Add(entityCategory);
                    }
                    entityCategory.RockEntities.Add(new MEntity {
                        Id = entity.Id, AssemblyName = entity.AssemblyName, FriendlyName = entity.FriendlyName
                    });
                }
            }

            EntityCategories = new List <MCategory>(entityCategories.Where(c => c.Name != "Other").OrderBy(c => c.Name));
            EntityCategories.AddRange(entityCategories.Where(c => c.Name == "Other"));
        }
        /// <summary>
        /// Shows the smart search view.
        /// </summary>
        private void ShowSmartSearchView()
        {
            var entitySetting = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchEntities");

            if (!string.IsNullOrWhiteSpace(entitySetting))
            {
                List <int> entityIds = entitySetting.Split(',').Select(int.Parse).ToList();

                var selected = string.Join(", ", EntityTypeCache.All().Where(e => entityIds.Contains(e.Id)).Select(e => e.FriendlyName).ToList());

                lSmartSearchEntities.Text = string.Join(",", EntityTypeCache.All().Where(e => entityIds.Contains(e.Id)).Select(e => e.FriendlyName).ToList());
            }
            lSmartSearchFilterCriteria.Text = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchFieldCriteria");

            var searchType = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType").ConvertToEnumOrNull <SearchType>() ?? SearchType.Wildcard;

            lSearchType.Text = searchType.ToString();
        }
Пример #10
0
        /// <summary>
        /// Gets the document URL.
        /// </summary>
        /// <returns></returns>
        public virtual string GetDocumentUrl(Dictionary <string, object> displayOptions = null)
        {
            // get template from entity type
            var sourceModelEntity = EntityTypeCache.All().Where(e => e.Name == this.SourceIndexModel).FirstOrDefault();

            if (sourceModelEntity != null)
            {
                var template = sourceModelEntity.IndexDocumentUrl;

                if (template.IsNotNullOrWhiteSpace())
                {
                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, null);
                    mergeFields.Add("IndexDocument", this);
                    mergeFields.Add("DisplayOptions", displayOptions);

                    return(template.ResolveMergeFields(mergeFields).Trim());
                }
            }

            return(string.Empty);;
        }
Пример #11
0
        /// <summary>
        /// Gets a list of the entity types that can be selected in the picker.
        /// </summary>
        /// <returns>A collection of ListItemViewModel objects that represent the entity types.</returns>
        private List <ListItemViewModel> GetEntityTypes()
        {
            var entityTypes = EntityTypeCache.All()
                              .Where(t => t.IsEntity)
                              .OrderByDescending(t => t.IsCommon)
                              .ThenBy(t => t.FriendlyName)
                              .Select(t => new ListItemViewModel
            {
                Value    = t.Guid.ToString(),
                Text     = t.FriendlyName,
                Category = t.IsCommon ? "Common" : "All Entities"
            })
                              .ToList();

            entityTypes.Insert(0, new ListItemViewModel
            {
                Value = Guid.Empty.ToString(),
                Text  = "None (Global Attributes)"
            });

            return(entityTypes);
        }
        /// <summary>
        /// Handles the Click event of the lbSmartSearchEdit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void lbSmartSearchEdit_Click(object sender, EventArgs e)
        {
            var entities          = EntityTypeCache.All();
            var indexableEntities = entities.Where(i => i.IsIndexingSupported == true).ToList();

            cblSmartSearchEntities.DataTextField  = "FriendlyName";
            cblSmartSearchEntities.DataValueField = "Id";
            cblSmartSearchEntities.DataSource     = indexableEntities;
            cblSmartSearchEntities.DataBind();

            var entitySetting = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchEntities");

            List <string> entityList = entitySetting.Split(',').ToList();

            foreach (ListItem checkbox in cblSmartSearchEntities.Items)
            {
                if (entityList.Contains(checkbox.Value))
                {
                    checkbox.Selected = true;
                }
            }

            tbSmartSearchFieldCrieria.Text = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchFieldCriteria");

            var searchType = ((int)SearchType.Wildcard).ToString();

            if (!string.IsNullOrWhiteSpace(Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType")))
            {
                searchType = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType");
            }

            ddlSearchType.SelectedValue = searchType;

            pnlSmartSearchEdit.Visible = true;
            pnlSmartSearchView.Visible = false;
        }
Пример #13
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that search commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            var parms = ParseMarkup(_markup, context);

            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            SearchType searchType = SearchType.Wildcard;

            List <int> entityIds = new List <int>();
            string     query     = string.Empty;

            int limit  = 50;
            int offset = 0;

            if (parms.Any(p => p.Key == "query"))
            {
                query = parms["query"];
            }

            if (parms.Any(p => p.Key == "limit"))
            {
                Int32.TryParse(parms["limit"], out limit);
            }

            if (parms.Any(p => p.Key == "offset"))
            {
                Int32.TryParse(parms["offset"], out offset);
            }

            if (parms.Any(p => p.Key == "fieldcriteria"))
            {
                foreach (var queryString in parms["fieldcriteria"].ToKeyValuePairList())
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split(',');

                    foreach (var value in values)
                    {
                        // the first letter of the field name should be lowercase
                        string fieldName = Char.ToLowerInvariant(queryString.Key[0]) + queryString.Key.Substring(1);
                        fieldCriteria.FieldValues.Add(new FieldValue {
                            Field = fieldName, Value = value
                        });
                    }
                }
            }

            if (parms.Any(p => p.Key == "searchtype"))
            {
                switch (parms["searchtype"])
                {
                case "exactmatch":
                {
                    searchType = SearchType.ExactMatch;
                    break;
                }

                case "fuzzy":
                {
                    searchType = SearchType.Fuzzy;
                    break;
                }

                case "wildcard":
                {
                    searchType = SearchType.Wildcard;
                    break;
                }
                }
            }

            if (parms.Any(p => p.Key == "criteriasearchtype"))
            {
                if (parms["criteriasearchtype"].ToLower() == "and")
                {
                    fieldCriteria.SearchType = CriteriaSearchType.And;
                }
            }

            if (parms.Any(p => p.Key == "entities"))
            {
                var entities = parms["entities"].Split(',');

                foreach (var entity in entities)
                {
                    foreach (var entityType in EntityTypeCache.All())
                    {
                        if (entityType.FriendlyName?.ToLower() == entity)
                        {
                            entityIds.Add(entityType.Id);
                        }
                    }
                }
            }

            var client  = IndexContainer.GetActiveComponent();
            var results = client.Search(query, searchType, entityIds, fieldCriteria, limit, offset);

            context.Scopes.Last()[parms["iterator"]] = results;

            base.Render(context, result);
        }
Пример #14
0
        /// <summary>
        /// Loads the Entity Attribute data.
        /// </summary>
        /// <param name="csvData">The CSV data.</param>
        private int LoadEntityAttributes(CSVInstance csvData)
        {
            var lookupContext      = new RockContext();
            var importedAttributes = new AttributeService(lookupContext).Queryable().Count(a => a.ForeignKey != null);
            var entityTypes        = EntityTypeCache.All().Where(e => e.IsEntity && e.IsSecured).ToList();
            var completedItems     = 0;
            var addedItems         = 0;

            ReportProgress(0, string.Format("Verifying attribute import ({0:N0} already imported).", importedAttributes));

            string[] row;
            // Uses a look-ahead enumerator: this call will move to the next record immediately
            while ((row = csvData.Database.FirstOrDefault()) != null)
            {
                var entityTypeName           = row[AttributeEntityTypeName];
                var attributeForeignKey      = row[AttributeId];
                var rockKey                  = row[AttributeRockKey];
                var attributeName            = row[AttributeName];
                var categoryName             = row[AttributeCategoryName];
                var attributeTypeString      = row[AttributeType];
                var definedValueForeignKey   = row[AttributeDefinedTypeId];
                var entityTypeQualifierName  = row[AttributeEntityTypeQualifierName];
                var entityTypeQualifierValue = row[AttributeEntityTypeQualifierValue];

                if (!string.IsNullOrWhiteSpace(entityTypeQualifierName) && !string.IsNullOrWhiteSpace(entityTypeQualifierValue))
                {
                    entityTypeQualifierValue = GetEntityTypeQualifierValue(entityTypeQualifierName, entityTypeQualifierValue, lookupContext);
                }

                if (string.IsNullOrEmpty(attributeName))
                {
                    LogException("Attribute", string.Format("Entity Attribute Name cannot be blank for {0} {1}", entityTypeName, attributeForeignKey));
                }
                else
                {
                    var entityTypeId          = entityTypes.FirstOrDefault(et => et.Name.Equals(entityTypeName)).Id;
                    var definedValueForeignId = definedValueForeignKey.AsType <int?>();
                    var fieldTypeId           = TextFieldTypeId;
                    fieldTypeId = GetAttributeFieldType(attributeTypeString);

                    var fk = string.Empty;
                    if (string.IsNullOrWhiteSpace(attributeForeignKey))
                    {
                        fk = string.Format("Bulldozer_{0}_{1}", categoryName.RemoveWhitespace(), attributeName.RemoveWhitespace()).Left(100);
                    }
                    else
                    {
                        fk = attributeForeignKey;
                    }

                    var attribute = FindEntityAttribute(lookupContext, categoryName, attributeName, entityTypeId, attributeForeignKey, rockKey);
                    if (attribute == null)
                    {
                        attribute = AddEntityAttribute(lookupContext, entityTypeId, entityTypeQualifierName, entityTypeQualifierValue, fk, categoryName, attributeName,
                                                       rockKey, fieldTypeId, true, definedValueForeignId, definedValueForeignKey, attributeTypeString: attributeTypeString);

                        addedItems++;
                    }
                    else if (string.IsNullOrWhiteSpace(attribute.ForeignKey))
                    {
                        attribute = AddEntityAttribute(lookupContext, entityTypeId, entityTypeQualifierName, entityTypeQualifierValue, fk, categoryName, attributeName,
                                                       rockKey, fieldTypeId, true, definedValueForeignId, definedValueForeignKey, attributeTypeString: attributeTypeString);

                        addedItems++;
                    }

                    completedItems++;
                    if (completedItems % (ReportingNumber * 10) < 1)
                    {
                        ReportProgress(0, string.Format("{0:N0} attributes processed.", completedItems));
                    }

                    if (completedItems % ReportingNumber < 1)
                    {
                        ReportPartialProgress();
                    }
                }
            }

            ReportProgress(100, string.Format("Finished attribute import: {0:N0} attributes imported.", addedItems));
            return(completedItems);
        }
Пример #15
0
        /// <summary>
        /// Cleanups the orphaned attributes.
        /// </summary>
        /// <param name="dataMap">The data map.</param>
        /// <returns></returns>
        private int CleanupOrphanedAttributes(JobDataMap dataMap)
        {
            int recordsDeleted = 0;

            // Cleanup AttributeMatrix records that are no longer associated with an attribute value
            using (RockContext rockContext = new RockContext())
            {
                AttributeMatrixService     attributeMatrixService     = new AttributeMatrixService(rockContext);
                AttributeMatrixItemService attributeMatrixItemService = new AttributeMatrixItemService(rockContext);

                var matrixFieldTypeId = FieldTypeCache.Read <MatrixFieldType>().Id;
                // get a list of attribute Matrix Guids that are actually in use
                var usedAttributeMatrices = new AttributeValueService(rockContext).Queryable().Where(a => a.Attribute.FieldTypeId == matrixFieldTypeId).Select(a => a.Value).ToList().AsGuidList();

                // clean up any orphaned attribute matrices
                var dayAgo = RockDateTime.Now.AddDays(-1);
                var orphanedAttributeMatrices = attributeMatrixService.Queryable().Where(a => (a.CreatedDateTime < dayAgo) && !usedAttributeMatrices.Contains(a.Guid)).ToList();
                if (orphanedAttributeMatrices.Any())
                {
                    recordsDeleted += orphanedAttributeMatrices.Count;
                    attributeMatrixItemService.DeleteRange(orphanedAttributeMatrices.SelectMany(a => a.AttributeMatrixItems));
                    attributeMatrixService.DeleteRange(orphanedAttributeMatrices);
                    rockContext.SaveChanges();
                }
            }

            // clean up other orphaned entity attributes
            Type rockContextType = typeof(Rock.Data.RockContext);

            foreach (var cachedType in EntityTypeCache.All().Where(e => e.IsEntity))
            {
                Type entityType = cachedType.GetEntityType();
                if (entityType != null &&
                    typeof(IEntity).IsAssignableFrom(entityType) &&
                    typeof(IHasAttributes).IsAssignableFrom(entityType) &&
                    !entityType.Namespace.Equals("Rock.Rest.Controllers"))
                {
                    try
                    {
                        bool ignore = false;
                        if (entityType.Assembly != rockContextType.Assembly)
                        {
                            // If the model is from a custom project, verify that it is using RockContext, if not, ignore it since an
                            // exception will occur due to the AttributeValue query using RockContext.
                            var entityContextType = Reflection.SearchAssembly(entityType.Assembly, typeof(System.Data.Entity.DbContext));
                            ignore = (entityContextType.Any() && !entityContextType.First().Value.Equals(rockContextType));
                        }

                        if (!ignore)
                        {
                            var classMethod = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
                                              .First(m => m.Name == "CleanupOrphanedAttributeValuesForEntityType");
                            var genericMethod = classMethod.MakeGenericMethod(entityType);
                            var result        = genericMethod.Invoke(this, null) as int?;
                            if (result.HasValue)
                            {
                                recordsDeleted += (int)result;
                            }
                        }
                    }
                    catch { }
                }
            }

            return(recordsDeleted);
        }
Пример #16
0
        /// <summary>
        /// Loads the Entity Attribute data.
        /// </summary>
        /// <param name="csvData">The CSV data.</param>
        private int LoadEntityAttributeValues(CSVInstance csvData)
        {
            var lookupContext           = new RockContext();
            var importedAttributeValues = new AttributeValueService(lookupContext).Queryable().Count(a => a.ForeignKey != null);
            var entityTypes             = EntityTypeCache.All().Where(e => e.IsEntity && e.IsSecured).ToList();
            var attributeService        = new AttributeService(lookupContext);
            var attributeValues         = new List <AttributeValue>();

            var completedItems = 0;
            var addedItems     = 0;

            int?      entityTypeId            = null;
            var       prevEntityTypeName      = string.Empty;
            var       prevAttributeForeignKey = string.Empty;
            var       prevRockKey             = string.Empty;
            Attribute attribute        = null;
            Type      contextModelType = null;

            System.Data.Entity.DbContext contextDbContext = null;
            IService       contextService             = null;
            IHasAttributes entity                     = null;
            var            prevAttributeValueEntityId = string.Empty;

            ReportProgress(0, string.Format("Verifying attribute value import ({0:N0} already imported).", importedAttributeValues));

            string[] row;
            // Uses a look-ahead enumerator: this call will move to the next record immediately
            while ((row = csvData.Database.FirstOrDefault()) != null)
            {
                var entityTypeName           = row[AttributeEntityTypeName];
                var attributeForeignKey      = row[AttributeId];
                var rockKey                  = row[AttributeRockKey];
                var attributeValueForeignKey = row[AttributeValueId];
                var attributeValueEntityId   = row[AttributeValueEntityId];
                var attributeValue           = row[AttributeValue];

                if (!string.IsNullOrWhiteSpace(entityTypeName) &&
                    !string.IsNullOrWhiteSpace(attributeValueEntityId) &&
                    !string.IsNullOrWhiteSpace(attributeValue) &&
                    (!string.IsNullOrEmpty(attributeForeignKey) || !string.IsNullOrEmpty(rockKey)))
                {
                    var findNewEntity = false;

                    if (!entityTypeId.HasValue || !prevEntityTypeName.Equals(entityTypeName, StringComparison.OrdinalIgnoreCase))
                    {
                        entityTypeId       = entityTypes.FirstOrDefault(et => et.Name.Equals(entityTypeName)).Id;
                        prevEntityTypeName = entityTypeName;
                        findNewEntity      = true;

                        contextModelType = entityTypes.FirstOrDefault(et => et.Name.Equals(entityTypeName)).GetEntityType();
                        contextDbContext = Reflection.GetDbContextForEntityType(contextModelType);
                        if (contextDbContext != null)
                        {
                            contextService = Reflection.GetServiceForEntityType(contextModelType, contextDbContext);
                        }
                    }

                    if (entityTypeId.HasValue && contextService != null)
                    {
                        if (!string.IsNullOrWhiteSpace(attributeForeignKey) && !prevAttributeForeignKey.Equals(attributeForeignKey, StringComparison.OrdinalIgnoreCase))
                        {
                            attribute = attributeService.GetByEntityTypeId(entityTypeId).FirstOrDefault(a => a.ForeignKey == attributeForeignKey);
                            prevAttributeForeignKey = attributeForeignKey;
                            prevRockKey             = string.Empty;
                        }
                        else if (string.IsNullOrWhiteSpace(attributeForeignKey))
                        {
                            // if no FK provided force attribute to null so the rockKey is tested
                            attribute = null;
                        }

                        if (attribute == null && !string.IsNullOrWhiteSpace(rockKey) && !prevRockKey.Equals(rockKey, StringComparison.OrdinalIgnoreCase))
                        {
                            attribute               = attributeService.GetByEntityTypeId(entityTypeId).FirstOrDefault(a => a.Key == rockKey);
                            prevRockKey             = rockKey;
                            prevAttributeForeignKey = string.Empty;
                        }

                        if (attribute != null)
                        {
                            // set the fk if it wasn't for some reason
                            if (string.IsNullOrWhiteSpace(attribute.ForeignKey) && !string.IsNullOrWhiteSpace(attributeForeignKey))
                            {
                                var updatedAttributeRockContext = new RockContext();
                                var updatedAttributeService     = new AttributeService(updatedAttributeRockContext);
                                var updatedAttribute            = updatedAttributeService.GetByEntityTypeId(entityTypeId).FirstOrDefault(a => a.Id == attribute.Id);
                                updatedAttribute.ForeignKey = attributeForeignKey;
                                updatedAttribute.ForeignId  = attributeForeignKey.AsIntegerOrNull();
                                updatedAttributeRockContext.SaveChanges(DisableAuditing);
                            }

                            if (entity == null || (findNewEntity || !prevAttributeValueEntityId.Equals(attributeValueEntityId, StringComparison.OrdinalIgnoreCase)))
                            {
                                MethodInfo qryMethod    = contextService.GetType().GetMethod("Queryable", new Type[] { });
                                var        entityQry    = qryMethod.Invoke(contextService, new object[] { }) as IQueryable <IEntity>;
                                var        entityResult = entityQry.Where(e => e.ForeignKey.Equals(attributeValueEntityId, StringComparison.OrdinalIgnoreCase));
                                entity = entityResult.FirstOrDefault() as IHasAttributes;
                                prevAttributeValueEntityId = attributeValueEntityId;
                            }

                            if (entity != null)
                            {
                                var av = CreateEntityAttributeValue(lookupContext, attribute, entity, attributeValue, attributeValueForeignKey);

                                if (av != null && !attributeValues.Where(e => e.EntityId == av.EntityId).Where(a => a.AttributeId == av.AttributeId).Any())
                                {
                                    attributeValues.Add(av);
                                    addedItems++;
                                }
                            }
                        }
                    }
                }

                completedItems++;
                if (completedItems % (ReportingNumber * 10) < 1)
                {
                    ReportProgress(0, string.Format("{0:N0} attribute values processed.", completedItems));
                }

                if (completedItems % ReportingNumber < 1)
                {
                    SaveAttributeValues(lookupContext, attributeValues);
                    attributeValues.Clear();
                    lookupContext.Dispose();
                    lookupContext    = new RockContext();
                    attributeService = new AttributeService(lookupContext);

                    ReportPartialProgress();
                }
            }

            if (attributeValues.Any())
            {
                SaveAttributeValues(lookupContext, attributeValues);
            }

            ReportProgress(100, string.Format("Finished attribute value import: {0:N0} attribute values imported.", addedItems));
            return(completedItems);
        }
Пример #17
0
        /// <summary>
        /// Loads the Notes data.
        /// </summary>
        /// <param name="csvData">The CSV data.</param>
        private int LoadNote(CSVInstance csvData)
        {
            var lookupContext = new RockContext();
            var importedNotes = new NoteService(lookupContext).Queryable().Count(n => n.ForeignKey != null);

            var entityTypes = EntityTypeCache.All().Where(e => e.IsEntity && e.IsSecured).ToList();

            var noteList     = new List <Note>();
            var skippedNotes = new Dictionary <string, string>();

            var completedItems = 0;

            ReportProgress(0, string.Format("Verifying note import ({0:N0} already imported).", importedNotes));

            string[] row;
            // Uses a look-ahead enumerator: this call will move to the next record immediately
            while ((row = csvData.Database.FirstOrDefault()) != null)
            {
                var noteType         = row[NoteType] as string;
                var entityTypeName   = row[EntityTypeName] as string;
                var entityForeignKey = row[EntityForeignId];
                var noteCaption      = row[NoteCaption] as string;
                var noteText         = row[NoteText] as string;
                var createdDate      = row[NoteDate].AsDateTime();
                var createdByKey     = row[CreatedById];
                var rowIsAlert       = row[IsAlert];
                var rowIsPrivate     = row[IsPrivate];

                var isAlert   = ( bool )ParseBoolOrDefault(rowIsAlert, false);
                var isPrivate = ( bool )ParseBoolOrDefault(rowIsPrivate, false);

                int?noteTypeId   = null;
                int?noteEntityId = null;
                var entityType   = entityTypes.FirstOrDefault(et => et.Name.Equals(entityTypeName));
                if (entityType != null)
                {
                    var entityTypeInstance = entityType.GetEntityType();
                    if (entityTypeInstance == typeof(Person))
                    {   // this is a person, reference the local keys that are already cached
                        var personKeys = GetPersonKeys(entityForeignKey);
                        if (personKeys != null)
                        {
                            noteEntityId = personKeys.PersonId;
                        }

                        noteTypeId = noteType.StartsWith("General", StringComparison.OrdinalIgnoreCase) ? ( int? )PersonalNoteTypeId : null;
                    }
                    else
                    {   // activate service type and query the foreign id for this entity type
                        var entityService   = Reflection.GetServiceForEntityType(entityTypeInstance, lookupContext);
                        var entityQueryable = entityService.GetType().GetMethod("Queryable", new Type[] { });

                        // Note: reflection-invoked service can only return IEnumerable or primitive object types
                        noteEntityId = ((IQueryable <IEntity>)entityQueryable.Invoke(entityService, new object[] { }))
                                       .Where(q => entityForeignKey == q.ForeignKey)
                                       .Select(q => q.Id)
                                       .FirstOrDefault();
                    }

                    if (noteEntityId > 0 && !string.IsNullOrWhiteSpace(noteText))
                    {
                        var creatorKeys    = GetPersonKeys(createdByKey);
                        var creatorAliasId = creatorKeys != null ? ( int? )creatorKeys.PersonAliasId : null;

                        var note = AddEntityNote(lookupContext, entityType.Id, ( int )noteEntityId, noteCaption, noteText, isAlert, isPrivate, noteType, noteTypeId, false, createdDate,
                                                 string.Format("Note imported {0}", ImportDateTime), creatorAliasId);

                        noteList.Add(note);
                        completedItems++;
                        if (completedItems % (ReportingNumber * 10) < 1)
                        {
                            ReportProgress(0, string.Format("{0:N0} notes processed.", completedItems));
                        }

                        if (completedItems % ReportingNumber < 1)
                        {
                            SaveNotes(noteList);
                            ReportPartialProgress();
                            noteList.Clear();
                        }
                    }
                }
                else
                {
                    skippedNotes.Add(entityForeignKey, noteType);
                }
            }

            if (noteList.Any())
            {
                SaveNotes(noteList);
            }

            if (skippedNotes.Any())
            {
                ReportProgress(0, "The following notes could not be imported and were skipped:");
                foreach (var key in skippedNotes)
                {
                    ReportProgress(0, string.Format("{0} note for Foreign ID {1}.", key.Value, key));
                }
            }

            ReportProgress(100, string.Format("Finished note import: {0:N0} notes imported.", completedItems));
            return(completedItems);
        }
Пример #18
0
        /// <summary>
        /// Configures the settings.
        /// </summary>
        private void ConfigureSettings()
        {
            // toggle refine search view toggle button
            lbRefineSearch.Visible = GetAttributeValue("ShowRefinedSearch").AsBoolean();

            // model selector
            var enabledModelIds = new List <int>();

            if (GetAttributeValue("EnabledModels").IsNotNullOrWhiteSpace())
            {
                enabledModelIds = GetAttributeValue("EnabledModels").Split(',').Select(int.Parse).ToList();
            }

            var entities          = EntityTypeCache.All();
            var indexableEntities = entities.Where(i => i.IsIndexingEnabled == true).ToList();

            // if enabled entities setting is set further filter by those
            if (enabledModelIds.Count > 0)
            {
                indexableEntities = indexableEntities.Where(i => enabledModelIds.Contains(i.Id)).ToList();
            }

            cblModelFilter.DataTextField  = "FriendlyName";
            cblModelFilter.DataValueField = "Id";
            cblModelFilter.DataSource     = indexableEntities;
            cblModelFilter.DataBind();

            cblModelFilter.Visible = GetAttributeValue("ShowFilters").AsBoolean();

            // if only one model is selected then hide the type checkbox
            if (cblModelFilter.Items.Count == 1)
            {
                cblModelFilter.Visible = false;
            }

            hrSeparator.Visible = cblModelFilter.Visible;

            ddlSearchType.BindToEnum <SearchType>();
            ddlSearchType.SelectedValue = GetAttributeValue("SearchType");

            // override the block setting if passed in the query string
            if (!string.IsNullOrWhiteSpace(PageParameter("SearchType")))
            {
                ddlSearchType.SelectedValue = PageParameter("SearchType");
            }

            // set setting values from query string
            if (!string.IsNullOrWhiteSpace(PageParameter("Models")))
            {
                var queryStringModels = PageParameter("Models").Split(',').Select(s => s.Trim()).ToList();

                foreach (ListItem item in cblModelFilter.Items)
                {
                    if (queryStringModels.Contains(item.Value))
                    {
                        item.Selected = true;
                    }
                    else
                    {
                        item.Selected = false;
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(PageParameter("ItemsPerPage")))
            {
                _itemsPerPage = PageParameter("ItemsPerPage").AsInteger();
            }

            if (!string.IsNullOrWhiteSpace(PageParameter("CurrentPage")))
            {
                _currentPageNum = PageParameter("CurrentPage").AsInteger() - 1;
            }

            if (!string.IsNullOrWhiteSpace(PageParameter("RefinedSearch")))
            {
                pnlRefineSearch.Visible = PageParameter("RefinedSearch").AsBoolean();

                if (pnlRefineSearch.Visible)
                {
                    lbRefineSearch.Text = "Hide Refined Search";
                }
            }

            _itemsPerPage = GetAttributeValue("ResultsPerPage").AsInteger();
        }
Пример #19
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        /// <exception cref="System.Exception">Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.</exception>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that entity commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            bool hasFilter = false;

            var modelName = string.Empty;

            // get a service for the entity based off it's friendly name
            if (_entityName == "business")
            {
                modelName = "Rock.Model.Person";
            }
            else
            {
                modelName = "Rock.Model." + _entityName;
            }

            // Check first to see if this is a core model. use the createIfNotFound = false option
            var entityTypeCache = EntityTypeCache.Get(modelName, false);

            if (entityTypeCache == null)
            {
                var entityTypes = EntityTypeCache.All();

                // If not, look for first plug-in model that has same friendly name
                entityTypeCache = entityTypes
                                  .Where(e =>
                                         e.IsEntity &&
                                         !e.Name.StartsWith("Rock.Model") &&
                                         e.FriendlyName != null &&
                                         e.FriendlyName.RemoveSpaces().ToLower() == _entityName)
                                  .OrderBy(e => e.Id)
                                  .FirstOrDefault();

                // If still null check to see if this was a duplicate class and full class name was used as entity name
                if (entityTypeCache == null)
                {
                    modelName       = _entityName.Replace('_', '.');
                    entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, modelName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                }
            }

            if (entityTypeCache != null)
            {
                Type entityType = entityTypeCache.GetEntityType();
                if (entityType != null)
                {
                    // Get the appropriate database context for this entity type.
                    // Note that this may be different from the standard RockContext if the entity is sourced from a plug-in.
                    var dbContext = Reflection.GetDbContextForEntityType(entityType);

                    // Check if there is a RockContext in the Lava context. If so then use the RockContext passed in.
                    if (dbContext is RockContext)
                    {
                        var lavaContext = context.Registers["RockContext"];

                        if (lavaContext.IsNotNull())
                        {
                            dbContext = (DbContext)lavaContext;
                        }
                    }

                    // Disable change-tracking for this data context to improve performance - objects supplied to a Lava context are read-only.
                    dbContext.Configuration.AutoDetectChangesEnabled = false;

                    // Create an instance of the entity's service
                    IService serviceInstance = Reflection.GetServiceForEntityType(entityType, dbContext);

                    ParameterExpression paramExpression = Expression.Parameter(entityType, "x");
                    Expression          queryExpression = null; // the base expression we'll use to build our query from

                    // Parse markup
                    var parms = ParseMarkup(_markup, context);

                    if (parms.Any(p => p.Key == "id"))
                    {
                        string propertyName = "Id";

                        List <string> selectionParms = new List <string>();
                        selectionParms.Add(PropertyComparisonConversion("==").ToString());
                        selectionParms.Add(parms["id"].ToString());
                        selectionParms.Add(propertyName);

                        var entityProperty = entityType.GetProperty(propertyName);
                        queryExpression = ExpressionHelper.PropertyFilterExpression(selectionParms, paramExpression, propertyName, entityProperty.PropertyType);

                        hasFilter = true;
                    }
                    else
                    {
                        // where clause expression
                        if (parms.Any(p => p.Key == "where"))
                        {
                            queryExpression = ParseWhere(parms["where"], entityType, serviceInstance, paramExpression, entityType, entityTypeCache);

                            if (queryExpression != null)
                            {
                                hasFilter = true;
                            }
                        }

                        // DataView expression
                        if (parms.Any(p => p.Key == "dataview"))
                        {
                            var dataViewId = parms["dataview"].AsIntegerOrNull();

                            if (dataViewId.HasValue)
                            {
                                var dataViewExpression = GetDataViewExpression(dataViewId.Value, serviceInstance, paramExpression, entityTypeCache);

                                if (queryExpression == null)
                                {
                                    queryExpression = dataViewExpression;
                                    hasFilter       = true;
                                }
                                else
                                {
                                    queryExpression = Expression.AndAlso(queryExpression, dataViewExpression);
                                }
                            }
                        }

                        // process dynamic filter expressions (from the query string)
                        if (parms.Any(p => p.Key == "dynamicparameters"))
                        {
                            var dynamicFilters = parms["dynamicparameters"].Split(',')
                                                 .Select(x => x.Trim())
                                                 .Where(x => !string.IsNullOrWhiteSpace(x))
                                                 .ToList();

                            foreach (var dynamicFilter in dynamicFilters)
                            {
                                var dynamicFilterValue      = HttpContext.Current.Request[dynamicFilter];
                                var dynamicFilterExpression = GetDynamicFilterExpression(dynamicFilter, dynamicFilterValue, entityType, serviceInstance, paramExpression);
                                if (dynamicFilterExpression != null)
                                {
                                    if (queryExpression == null)
                                    {
                                        queryExpression = dynamicFilterExpression;
                                        hasFilter       = true;
                                    }
                                    else
                                    {
                                        queryExpression = Expression.AndAlso(queryExpression, dynamicFilterExpression);
                                    }
                                }
                            }
                        }
                    }

                    // Make the query from the expression.

                    /* [2020-10-08] DL
                     * "Get" is intentionally used here rather than "GetNoTracking" to allow lazy-loading of navigation properties from the Lava context.
                     * (Refer https://github.com/SparkDevNetwork/Rock/issues/4293)
                     */
                    MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty), typeof(int?) });

                    if (getMethod != null)
                    {
                        // get a listing of ids and build it into the query expression
                        if (parms.Any(p => p.Key == "ids"))
                        {
                            List <int>         value = parms["ids"].ToString().Split(',').Select(int.Parse).ToList();
                            MemberExpression   propertyExpression = Expression.Property(paramExpression, "Id");
                            ConstantExpression constantExpression = Expression.Constant(value, typeof(List <int>));
                            Expression         containsExpression = Expression.Call(constantExpression, typeof(List <int>).GetMethod("Contains", new Type[] { typeof(int) }), propertyExpression);
                            if (queryExpression != null)
                            {
                                queryExpression = Expression.AndAlso(queryExpression, containsExpression);
                            }
                            else
                            {
                                queryExpression = containsExpression;
                            }

                            hasFilter = true;
                        }

                        var getResult   = getMethod.Invoke(serviceInstance, new object[] { paramExpression, queryExpression, null, null });
                        var queryResult = getResult as IQueryable <IEntity>;

                        // process entity specific filters
                        switch (_entityName)
                        {
                        case "person":
                        {
                            queryResult = PersonFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }

                        case "business":
                        {
                            queryResult = BusinessFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }
                        }

                        // if there was a dynamic expression add it now
                        if (parms.Any(p => p.Key == "expression"))
                        {
                            queryResult = queryResult.Where(parms["expression"]);
                            hasFilter   = true;
                        }

                        var queryResultExpression = queryResult.Expression;

                        // add sort expressions
                        if (parms.Any(p => p.Key == "sort"))
                        {
                            string orderByMethod = "OrderBy";

                            foreach (var column in parms["sort"].Split(',').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList())
                            {
                                string propertyName;
                                var    direction = SortDirection.Ascending;

                                if (column.EndsWith(" desc", StringComparison.OrdinalIgnoreCase))
                                {
                                    direction    = SortDirection.Descending;
                                    propertyName = column.Left(column.Length - 5);
                                }
                                else
                                {
                                    propertyName = column;
                                }

                                string methodName = direction == SortDirection.Descending ? orderByMethod + "Descending" : orderByMethod;

                                if (entityType.GetProperty(propertyName) != null)
                                {
                                    // sorting a entity property
                                    var memberExpression          = Expression.Property(paramExpression, propertyName);
                                    LambdaExpression sortSelector = Expression.Lambda(memberExpression, paramExpression);
                                    queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                }
                                else
                                {
                                    // sorting on an attribute

                                    // get attribute id
                                    int?attributeId = null;
                                    foreach (var attribute in AttributeCache.GetByEntityType(entityTypeCache.Id))
                                    {
                                        if (attribute.Key == propertyName)
                                        {
                                            attributeId = attribute.Id;
                                            break;
                                        }
                                    }

                                    if (attributeId.HasValue)
                                    {
                                        // get AttributeValue queryable and parameter
                                        if (dbContext is RockContext)
                                        {
                                            var attributeValues = new AttributeValueService(dbContext as RockContext).Queryable();
                                            ParameterExpression attributeValueParameter = Expression.Parameter(typeof(AttributeValue), "v");
                                            MemberExpression    idExpression            = Expression.Property(paramExpression, "Id");
                                            var attributeExpression = Attribute.Helper.GetAttributeValueExpression(attributeValues, attributeValueParameter, idExpression, attributeId.Value);

                                            LambdaExpression sortSelector = Expression.Lambda(attributeExpression, paramExpression);
                                            queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                        }
                                        else
                                        {
                                            throw new Exception(string.Format("The database context for type {0} does not support RockContext attribute value queries.", entityTypeCache.FriendlyName));
                                        }
                                    }
                                }

                                orderByMethod = "ThenBy";
                            }
                        }

                        // check to ensure we had some form of filter (otherwise we'll return all results in the table)
                        if (!hasFilter)
                        {
                            throw new Exception("Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.");
                        }

                        // reassemble the queryable with the sort expressions
                        queryResult = queryResult.Provider.CreateQuery(queryResultExpression) as IQueryable <IEntity>;

                        if (parms.GetValueOrNull("count").AsBoolean())
                        {
                            int countResult = queryResult.Count();
                            context.Scopes.Last()["count"] = countResult;
                        }
                        else
                        {
                            // Run security check on each result if enabled and entity is not a person (we do not check security on people)
                            if (parms["securityenabled"].AsBoolean() && _entityName != "person")
                            {
                                var items        = queryResult.ToList();
                                var itemsSecured = new List <IEntity>();

                                Person person = GetCurrentPerson(context);

                                foreach (IEntity item in items)
                                {
                                    ISecured itemSecured = item as ISecured;
                                    if (itemSecured == null || itemSecured.IsAuthorized(Authorization.VIEW, person))
                                    {
                                        itemsSecured.Add(item);

                                        /*
                                         *      8/13/2020 - JME
                                         *      It might seem logical to break out of the loop if there is limit parameter provided once the
                                         *  limit is reached. This though has two issues.
                                         *
                                         *  FIRST
                                         *  Depending how it was implemented it can have the effect of breaking when an offset is
                                         *  provided.
                                         *          {% contentchannelitem where:'ContentChannelId == 1' limit:'3' %}
                                         *          {% for item in contentchannelitemItems %}
                                         *              {{ item.Id }} - {{ item.Title }}<br>
                                         *          {% endfor %}
                                         *      {% endcontentchannelitem %}
                                         *  Returns 3 items (correct)
                                         *
                                         *      {% contentchannelitem where:'ContentChannelId == 1' limit:'3' offset:'1' %}
                                         *          {% for item in contentchannelitemItems %}
                                         *              {{ item.Id }} - {{ item.Title }}<br>
                                         *          {% endfor %}
                                         *      {% endcontentchannelitem %}
                                         *  Returns only 2 items (incorrect) - because of the offset
                                         *
                                         *  SECOND
                                         *  If the limit is moved before the security check it's possible that the security checks
                                         *  will remove items and will therefore not give you the amount of items that you asked for.
                                         *
                                         *  Unfortunately this has to be an inefficent process to ensure pagination works. I will also
                                         *  add a detailed note to the documentation to encourage people to disable security checks,
                                         *  especially when used with pagination, in the Lava docs.
                                         */
                                    }
                                }

                                queryResult = itemsSecured.AsQueryable();
                            }

                            // offset
                            if (parms.Any(p => p.Key == "offset"))
                            {
                                queryResult = queryResult.Skip(parms["offset"].AsInteger());
                            }

                            // limit, default to 1000
                            if (parms.Any(p => p.Key == "limit"))
                            {
                                queryResult = queryResult.Take(parms["limit"].AsInteger());
                            }
                            else
                            {
                                queryResult = queryResult.Take(1000);
                            }

                            var resultList = queryResult.ToList();

                            // if there is only one item to return set an alternative non-array based variable
                            if (resultList.Count == 1)
                            {
                                context.Scopes.Last()[_entityName] = resultList.FirstOrDefault();
                            }

                            context.Scopes.Last()[parms["iterator"]] = resultList;
                        }
                    }
                }
            }
            else
            {
                result.Write(string.Format("Could not find a model for {0}.", _entityName));
                base.Render(context, result);
            }

            base.Render(context, result);
        }
Пример #20
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        /// <exception cref="System.Exception">Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.</exception>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that entity commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            bool hasFilter = false;

            // get a service for the entity based off it's friendly name
            var entityTypes = EntityTypeCache.All();

            var model = string.Empty;

            if (_entityName == "business")
            {
                model = "Rock.Model.Person";
            }
            else
            {
                model = "Rock.Model." + _entityName;
            }

            // Check first to see if this is a core model
            var entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            // If not, look for first plugin model that has same friendly name
            if (entityTypeCache == null)
            {
                entityTypeCache = entityTypes
                                  .Where(e =>
                                         e.IsEntity &&
                                         !e.Name.StartsWith("Rock.Model") &&
                                         e.FriendlyName != null &&
                                         e.FriendlyName.RemoveSpaces().ToLower() == _entityName)
                                  .OrderBy(e => e.Id)
                                  .FirstOrDefault();
            }

            // If still null check to see if this was a duplicate class and full class name was used as entity name
            if (entityTypeCache == null)
            {
                model           = _entityName.Replace('_', '.');
                entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            }

            if (entityTypeCache != null)
            {
                Type entityType = entityTypeCache.GetEntityType();
                if (entityType != null)
                {
                    // Get the database context
                    Type contextType = null;
                    Rock.Data.DbContext dbContext = null;
                    var contexts = Rock.Reflection.SearchAssembly(entityType.Assembly, typeof(Rock.Data.DbContext));
                    if (contexts.Any())
                    {
                        contextType = contexts.First().Value;
                        dbContext   = Activator.CreateInstance(contextType) as Rock.Data.DbContext;
                    }
                    if (dbContext == null)
                    {
                        dbContext = _rockContext;
                    }

                    // create an instance of the entity's service
                    Type[]             modelType          = { entityType };
                    Type               genericServiceType = typeof(Rock.Data.Service <>);
                    Type               modelServiceType   = genericServiceType.MakeGenericType(modelType);
                    Rock.Data.IService serviceInstance    = Activator.CreateInstance(modelServiceType, new object[] { dbContext }) as IService;

                    ParameterExpression paramExpression = Expression.Parameter(entityType, "x");
                    Expression          queryExpression = null; // the base expression we'll use to build our query from

                    // parse markup
                    var parms = ParseMarkup(_markup, context);

                    if (parms.Any(p => p.Key == "id"))
                    {
                        string propertyName = "Id";

                        List <string> selectionParms = new List <string>();
                        selectionParms.Add(PropertyComparisonConverstion("==").ToString());
                        selectionParms.Add(parms["id"].ToString());
                        selectionParms.Add(propertyName);

                        var entityProperty = entityType.GetProperty(propertyName);
                        queryExpression = ExpressionHelper.PropertyFilterExpression(selectionParms, paramExpression, propertyName, entityProperty.PropertyType);

                        hasFilter = true;
                    }
                    else
                    {
                        // where clause expression
                        if (parms.Any(p => p.Key == "where"))
                        {
                            queryExpression = ParseWhere(parms["where"], entityType, serviceInstance, paramExpression, entityType, entityTypeCache);

                            if (queryExpression != null)
                            {
                                hasFilter = true;
                            }
                        }

                        // dataview expression
                        if (parms.Any(p => p.Key == "dataview"))
                        {
                            var dataViewId = parms["dataview"].AsIntegerOrNull();

                            if (dataViewId.HasValue)
                            {
                                var dataViewExpression = GetDataViewExpression(dataViewId.Value, serviceInstance, paramExpression, entityTypeCache);

                                if (queryExpression == null)
                                {
                                    queryExpression = dataViewExpression;
                                    hasFilter       = true;
                                }
                                else
                                {
                                    queryExpression = Expression.AndAlso(queryExpression, dataViewExpression);
                                }
                            }
                        }

                        // process dynamic filter expressions (from the query string)
                        if (parms.Any(p => p.Key == "dynamicparameters"))
                        {
                            var dynamicFilters = parms["dynamicparameters"].Split(',')
                                                 .Select(x => x.Trim())
                                                 .Where(x => !string.IsNullOrWhiteSpace(x))
                                                 .ToList();

                            foreach (var dynamicFilter in dynamicFilters)
                            {
                                var dynamicFilterValue      = HttpContext.Current.Request[dynamicFilter];
                                var dynamicFilterExpression = GetDynamicFilterExpression(dynamicFilter, dynamicFilterValue, entityType, serviceInstance, paramExpression);
                                if (dynamicFilterExpression != null)
                                {
                                    if (queryExpression == null)
                                    {
                                        queryExpression = dynamicFilterExpression;
                                        hasFilter       = true;
                                    }
                                    else
                                    {
                                        queryExpression = Expression.AndAlso(queryExpression, dynamicFilterExpression);
                                    }
                                }
                            }
                        }
                    }

                    // make the query from the expression
                    MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty), typeof(int?) });
                    if (getMethod != null)
                    {
                        var queryResult = getMethod.Invoke(serviceInstance, new object[] { paramExpression, queryExpression, null, null }) as IQueryable <IEntity>;

                        // process entity specific filters
                        switch (_entityName)
                        {
                        case "person":
                        {
                            queryResult = PersonFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }

                        case "business":
                        {
                            queryResult = BusinessFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }
                        }

                        // if there was a dynamic expression add it now
                        if (parms.Any(p => p.Key == "expression"))
                        {
                            queryResult = queryResult.Where(parms["expression"]);
                            hasFilter   = true;
                        }

                        // get a listing of ids
                        if (parms.Any(p => p.Key == "ids"))
                        {
                            var value = parms["ids"].ToString().Split(',').Select(int.Parse).ToList();
                            queryResult = queryResult.Where(x => value.Contains(x.Id));
                            hasFilter   = true;
                        }

                        var queryResultExpression = queryResult.Expression;

                        // add sort expressions
                        if (parms.Any(p => p.Key == "sort"))
                        {
                            string orderByMethod = "OrderBy";


                            foreach (var column in parms["sort"].Split(',').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList())
                            {
                                string propertyName;
                                var    direction = SortDirection.Ascending;

                                if (column.EndsWith(" desc", StringComparison.OrdinalIgnoreCase))
                                {
                                    direction    = SortDirection.Descending;
                                    propertyName = column.Left(column.Length - 5);
                                }
                                else
                                {
                                    propertyName = column;
                                }

                                string methodName = direction == SortDirection.Descending ? orderByMethod + "Descending" : orderByMethod;

                                if (entityType.GetProperty(propertyName) != null)
                                {
                                    // sorting a entity property
                                    var memberExpression          = Expression.Property(paramExpression, propertyName);
                                    LambdaExpression sortSelector = Expression.Lambda(memberExpression, paramExpression);
                                    queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                }
                                else
                                {
                                    // sorting on an attribute

                                    // get attribute id
                                    int?attributeId = null;
                                    foreach (var id in AttributeCache.GetByEntity(entityTypeCache.Id).SelectMany(a => a.AttributeIds))
                                    {
                                        var attribute = AttributeCache.Get(id);
                                        if (attribute.Key == propertyName)
                                        {
                                            attributeId = id;
                                        }
                                    }

                                    if (attributeId.HasValue)
                                    {
                                        // get AttributeValue queryable and parameter
                                        var attributeValues = _rockContext.Set <AttributeValue>();
                                        ParameterExpression attributeValueParameter = Expression.Parameter(typeof(AttributeValue), "v");
                                        MemberExpression    idExpression            = Expression.Property(paramExpression, "Id");
                                        var attributeExpression = Attribute.Helper.GetAttributeValueExpression(attributeValues, attributeValueParameter, idExpression, attributeId.Value);

                                        LambdaExpression sortSelector = Expression.Lambda(attributeExpression, paramExpression);
                                        queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                    }
                                }

                                orderByMethod = "ThenBy";
                            }
                        }

                        // reassemble the queryable with the sort expressions
                        queryResult = queryResult.Provider.CreateQuery(queryResultExpression) as IQueryable <IEntity>;

                        if (parms.GetValueOrNull("count").AsBoolean())
                        {
                            int countResult = queryResult.Count();
                            context.Scopes.Last()["count"] = countResult;
                        }
                        else
                        {
                            // run security check on each result
                            var items        = queryResult.ToList();
                            var itemsSecured = new List <IEntity>();

                            Person person = GetCurrentPerson(context);

                            foreach (IEntity item in items)
                            {
                                ISecured itemSecured = item as ISecured;
                                if (itemSecured == null || itemSecured.IsAuthorized(Authorization.VIEW, person))
                                {
                                    itemsSecured.Add(item);
                                }
                            }

                            queryResult = itemsSecured.AsQueryable();

                            // offset
                            if (parms.Any(p => p.Key == "offset"))
                            {
                                queryResult = queryResult.Skip(parms["offset"].AsInteger());
                            }

                            // limit, default to 1000
                            if (parms.Any(p => p.Key == "limit"))
                            {
                                queryResult = queryResult.Take(parms["limit"].AsInteger());
                            }
                            else
                            {
                                queryResult = queryResult.Take(1000);
                            }

                            // check to ensure we had some form of filter (otherwise we'll return all results in the table)
                            if (!hasFilter)
                            {
                                throw new Exception("Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.");
                            }

                            var resultList = queryResult.ToList();

                            // if there is only one item to return set an alternative non-array based variable
                            if (resultList.Count == 1)
                            {
                                context.Scopes.Last()[_entityName] = resultList.FirstOrDefault();
                            }

                            context.Scopes.Last()[parms["iterator"]] = resultList;
                        }
                    }
                }
            }
            else
            {
                result.Write(string.Format("Could not find a model for {0}.", _entityName));
                base.Render(context, result);
            }

            base.Render(context, result);
        }
Пример #21
0
        /// <summary>
        /// Searches the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="searchType">Type of the search.</param>
        /// <param name="entities">The entities.</param>
        /// <param name="fieldCriteria">The field criteria.</param>
        /// <param name="size">The size.</param>
        /// <param name="from">From.</param>
        /// <param name="totalResultsAvailable">The total results available.</param>
        /// <returns></returns>
        public override List <IndexModelBase> Search(string query, SearchType searchType, List <int> entities, SearchFieldCriteria fieldCriteria, int?size, int?from, out long totalResultsAvailable)
        {
            List <IndexModelBase> documents = new List <IndexModelBase>();

            totalResultsAvailable = 0;
            bool allEntities = false;

            BooleanQuery  queryContainer  = new BooleanQuery();
            List <string> combinedFields  = new List <string>();
            List <Type>   indexModelTypes = new List <Type>();
            Dictionary <string, Analyzer> combinedFieldAnalyzers = new Dictionary <string, Analyzer>();

            using (RockContext rockContext = new RockContext())
            {
                var entityTypeService = new EntityTypeService(rockContext);
                if (entities == null || entities.Count == 0)
                {
                    //add all entities
                    allEntities = true;
                    var selectedEntityTypes = EntityTypeCache.All().Where(e => e.IsIndexingSupported && e.IsIndexingEnabled && e.FriendlyName != "Site");

                    foreach (var entityTypeCache in selectedEntityTypes)
                    {
                        entities.Add(entityTypeCache.Id);
                    }
                }

                foreach (var entityId in entities)
                {
                    // get entities search model name
                    var entityType = entityTypeService.GetNoTracking(entityId);
                    indexModelTypes.Add(entityType.IndexModelType);

                    // check if this is a person model, if so we need to add two model types one for person and the other for businesses
                    // wish there was a cleaner way to do this
                    if (entityType.Guid == SystemGuid.EntityType.PERSON.AsGuid())
                    {
                        indexModelTypes.Add(typeof(BusinessIndex));
                    }
                }

                indexModelTypes = indexModelTypes.Distinct().ToList();
                CombineIndexTypes(indexModelTypes, out combinedFields, out combinedFieldAnalyzers);

                if (entities != null && entities.Count != 0 && !allEntities)
                {
                    var indexModelTypesQuery = new BooleanQuery();
                    indexModelTypes.ForEach(f => indexModelTypesQuery.Add(new TermQuery(new Term("type", f.Name.ToLower())), Occur.SHOULD));
                    queryContainer.Add(indexModelTypesQuery, Occur.MUST);
                }
            }

            TopDocs topDocs = null;
            // Use the analyzer in fieldAnalyzers if that field is in that dictionary, otherwise use StandardAnalyzer.
            PerFieldAnalyzerWrapper analyzer = new PerFieldAnalyzerWrapper(defaultAnalyzer: new StandardAnalyzer(_matchVersion), fieldAnalyzers: combinedFieldAnalyzers);

            if (fieldCriteria != null && fieldCriteria.FieldValues?.Count > 0)
            {
                Occur occur = fieldCriteria.SearchType == CriteriaSearchType.And ? Occur.MUST : Occur.SHOULD;
                foreach (var match in fieldCriteria.FieldValues)
                {
                    BooleanClause booleanClause = new BooleanClause(new TermQuery(new Term(match.Field, match.Value)), occur);
                    booleanClause.Query.Boost = match.Boost;
                    queryContainer.Add(booleanClause);
                }
            }

            switch (searchType)
            {
            case SearchType.ExactMatch:
            {
                var wordQuery = new BooleanQuery();

                if (!string.IsNullOrWhiteSpace(query))
                {
                    var words = query.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var word in words)
                    {
                        var innerQuery = new BooleanQuery();
                        combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, word.ToLower())), Occur.SHOULD));
                        wordQuery.Add(innerQuery, Occur.SHOULD);
                    }
                }

                if (wordQuery.Count() != 0)
                {
                    queryContainer.Add(wordQuery, Occur.MUST);
                }

                // special logic to support emails
                if (query.Contains("@"))
                {
                    queryContainer.Add(new BooleanClause(new TermQuery(new Term("Email", query)), Occur.SHOULD));
                }

                // special logic to support phone search
                if (query.IsDigitsOnly())
                {
                    queryContainer.Add(new BooleanClause(new WildcardQuery(new Term("PhoneNumbers", "*" + query + "*")), Occur.SHOULD));
                }

                // add a search for all the words as one single search term
                foreach (var field in combinedFields)
                {
                    var phraseQuery = new PhraseQuery();
                    phraseQuery.Add(new Term(field, query.ToLower()));
                    queryContainer.Add(phraseQuery, Occur.SHOULD);
                }

                break;
            }

            case SearchType.Fuzzy:
            {
                foreach (var field in combinedFields)
                {
                    queryContainer.Add(new FuzzyQuery(new Term(field, query.ToLower())), Occur.SHOULD);
                }

                break;
            }

            case SearchType.Wildcard:
            {
                bool enablePhraseSearch = true;

                if (!string.IsNullOrWhiteSpace(query))
                {
                    BooleanQuery wildcardQuery = new BooleanQuery();

                    // break each search term into a separate query and add the * to the end of each
                    var queryTerms = query.Split(' ').Select(p => p.Trim()).ToList();

                    // special logic to support emails
                    if (queryTerms.Count == 1 && query.Contains("@"))
                    {
                        wildcardQuery.Add(new WildcardQuery(new Term("Email", "*" + query.ToLower() + "*")), Occur.SHOULD);
                        enablePhraseSearch = false;
                    }
                    else
                    {
                        foreach (var queryTerm in queryTerms)
                        {
                            if (!string.IsNullOrWhiteSpace(queryTerm))
                            {
                                var innerQuery = new BooleanQuery();
                                combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, queryTerm.ToLower())), Occur.SHOULD));
                                wildcardQuery.Add(innerQuery, Occur.MUST);
                            }
                        }

                        // add special logic to help boost last names
                        if (queryTerms.Count() > 1 && (indexModelTypes.Contains(typeof(PersonIndex)) || indexModelTypes.Contains(typeof(BusinessIndex))))
                        {
                            BooleanQuery nameQuery = new BooleanQuery
                            {
                                { new PrefixQuery(new Term("FirstName", queryTerms.First().ToLower())), Occur.MUST },
                                { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower()))
                                  {
                                      Boost = 30
                                  }, Occur.MUST }
                            };
                            wildcardQuery.Add(nameQuery, Occur.SHOULD);

                            nameQuery = new BooleanQuery
                            {
                                { new PrefixQuery(new Term("NickName", queryTerms.First().ToLower())), Occur.MUST },
                                { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower()))
                                  {
                                      Boost = 30
                                  }, Occur.MUST }
                            };
                            wildcardQuery.Add(nameQuery, Occur.SHOULD);
                        }

                        // special logic to support phone search
                        if (query.IsDigitsOnly())
                        {
                            wildcardQuery.Add(new PrefixQuery(new Term("PhoneNumbers", queryTerms.First().ToLower())), Occur.SHOULD);
                        }
                    }

                    queryContainer.Add(wildcardQuery, Occur.MUST);
                }

                // add a search for all the words as one single search term
                if (enablePhraseSearch)
                {
                    // add a search for all the words as one single search term
                    foreach (var field in combinedFields)
                    {
                        var phraseQuery = new PhraseQuery();
                        phraseQuery.Add(new Term(field, query.ToLower()));
                        queryContainer.Add(phraseQuery, Occur.SHOULD);
                    }
                }

                break;
            }
            }

            int returnSize = 10;

            if (size.HasValue)
            {
                returnSize = size.Value;
            }

            OpenReader();

            if (from.HasValue)
            {
                TopScoreDocCollector collector = TopScoreDocCollector.Create(returnSize * 10, true);   // Search for 10 pages with returnSize entries in each page
                _indexSearcher.Search(queryContainer, collector);
                topDocs = collector.GetTopDocs(from.Value, returnSize);
            }
            else
            {
                topDocs = _indexSearcher.Search(queryContainer, returnSize);
            }

            totalResultsAvailable = topDocs.TotalHits;

            if (topDocs != null)
            {
                foreach (var hit in topDocs.ScoreDocs)
                {
                    var document = LuceneDocToIndexModel(queryContainer, hit);
                    if (document != null)
                    {
                        documents.Add(document);
                    }
                }
            }

            return(documents);
        }