Beispiel #1
0
        /// <summary>
        /// Get a Root CMS Block if you have the ModuleInfo object.
        /// </summary>
        /// <param name="container"></param>
        /// <param name="parentLog">optional logger to attach to</param>
        /// <returns>An initialized CMS Block, ready to use/render</returns>
        public static IBlockBuilder CmsBlock(IContainer container, ILog parentLog = null)
        {
            var dnnModule = ((Container <ModuleInfo>)container).UnwrappedContents;
            var tenant    = new DnnTenant(new PortalSettings(dnnModule.OwnerPortalID));

            return(new BlockFromModule().Init(new DnnContext(tenant, container, new DnnUser()), parentLog).BlockBuilder);
        }
Beispiel #2
0
        private Tuple <App, PermissionCheckBase> AppAndPermissionChecker(int appId, string typeName)
        {
            var env      = Factory.Resolve <IEnvironmentFactory>().Environment(Log);
            var tenant   = new DnnTenant(PortalSettings.Current);
            var uiZoneId = env.ZoneMapper.GetZoneId(tenant.Id);

            // now do relevant security checks

            var zoneId = SystemManager.ZoneIdOfApp(appId);
            var app    = new App(tenant, zoneId, appId, parentLog: Log);

            var type = typeName == null
                ? null
                : new AppRuntime(zoneId, appId, Log)
                       .ContentTypes.Get(typeName);

            var samePortal            = uiZoneId == tenant.Id;
            var portalToUseInSecCheck = samePortal ? PortalSettings.Current : null;

            // user has edit permissions on this app, and it's the same app as the user is coming from
            var checker = new DnnPermissionCheck(Log,
                                                 instance: SxcInstance.EnvInstance,
                                                 app: app,
                                                 portal: portalToUseInSecCheck,
                                                 targetType: type);

            return(new Tuple <App, PermissionCheckBase>(app, checker));
        }
Beispiel #3
0
        public IEnumerable <AppUiInfo> GetSelectableApps(string apps = null)
        {
            // Note: we must get the zone-id from the tenant, since the app may not yet exist when inserted the first time
            var tenant = new DnnTenant(PortalSettings);

            return(new CmsZones(tenant.ZoneId, Log).AppsRt.GetSelectableApps(tenant, apps).ToList());
        }
Beispiel #4
0
        private void PrepCore(App app, Guid entityGuid, string fieldName, bool usePortalRoot)
        {
            var tenant = new DnnTenant(Dnn.Portal);

            AdamAppContext   = new AdamAppContext(tenant, app, SxcInstance);
            ContainerContext = usePortalRoot
                ? new ContainerOfTenant(AdamAppContext) as ContainerBase
                : new ContainerOfField(AdamAppContext, entityGuid, fieldName);
        }
Beispiel #5
0
        private void PrepCore(IApp app, Guid entityGuid, string fieldName, bool usePortalRoot)
        {
            Log.Add("PrepCore(...)");
            var dnn    = new DnnContext(BlockBuilder?.Container);
            var tenant = new DnnTenant(dnn.Portal);

            AdamAppContext   = new AdamAppContext(tenant, app, BlockBuilder, 10, Log);
            ContainerContext = usePortalRoot
                ? new ContainerOfTenant(AdamAppContext) as ContainerBase
                : new ContainerOfField(AdamAppContext, entityGuid, fieldName);
        }
Beispiel #6
0
        private void PrepCore(App app, Guid entityGuid, string fieldName, bool usePortalRoot)
        {
            Log.Add("PrepCore(...)");
            var dnn    = new DnnHelper(SxcInstance?.EnvInstance);
            var tenant = new DnnTenant(dnn.Portal);

            AdamAppContext   = new AdamAppContext(tenant, app, SxcInstance, Log);
            ContainerContext = usePortalRoot
                ? new ContainerOfTenant(AdamAppContext) as ContainerBase
                : new ContainerOfField(AdamAppContext, entityGuid, fieldName);
        }
Beispiel #7
0
        public override XmlExporter Init(int zoneId, int appId, AppRuntime appRuntime, bool appExport, string[] attrSetIds, string[] entityIds, Log parentLog)
        {
            var tenant = new DnnTenant(PortalSettings.Current);
            var app    = new App(tenant, zoneId, appId);

            AdamAppContext = new AdamAppContext(tenant, app, null);
            Constructor(zoneId, appRuntime, app.AppGuid, appExport, attrSetIds, entityIds, parentLog);

            // this must happen very early, to ensure that the file-lists etc. are correct for exporting when used externally
            InitExportXDocument(PortalSettings.Current.DefaultLanguage, Settings.ModuleVersion);

            return(this);
        }
Beispiel #8
0
        protected MultiPermissionsApp(IBlockBuilder blockBuilder, int zoneId, int appId, ILog parentLog)
            : base("Api.Perms", parentLog)
        {
            var wrapLog = Log.Call($"..., appId: {appId}, ...");

            BlockBuilder = blockBuilder;
            var tenant        = new DnnTenant(PortalSettings.Current);
            var environment   = Factory.Resolve <IEnvironmentFactory>().Environment(Log);
            var contextZoneId = environment.ZoneMapper.GetZoneId(tenant.Id);

            App = new App(tenant, zoneId, appId,
                          ConfigurationProvider.Build(blockBuilder, true),
                          false, Log);
            SamePortal             = contextZoneId == zoneId;
            PortalForSecurityCheck = SamePortal ? PortalSettings.Current : null;
            wrapLog($"ready for z/a:{zoneId}/{appId} t/z:{tenant.Id}/{contextZoneId} same:{SamePortal}");
        }
        public dynamic Apps(int zoneId)
        {
            var cms    = new CmsZones(zoneId, Env, Log);
            var tenant = new DnnTenant(new PortalSettings(ActiveModule.OwnerPortalID));
            var configurationBuilder = ConfigurationProvider.Build(BlockBuilder, true);
            var list = cms.AppsRt.GetApps(tenant, configurationBuilder);

            return(list.Select(a => new
            {
                Id = a.AppId,
                IsApp = a.AppGuid != Eav.Constants.DefaultAppName,
                Guid = a.AppGuid,
                a.Name,
                a.Folder,
                AppRoot = a.Path,
                IsHidden = a.Hidden,
                ConfigurationId = a.Configuration?.Id,
                Items = a.Data.List.Count(),
                a.Thumbnail,
                Version = a.VersionSafe()
            }).ToList());
        }
Beispiel #10
0
        public IEnumerable <AppUiInfo> GetSelectableApps(string apps = null)
        {
            // we must get the zone-id from the environment,
            // since the app may not yet exist when inserted the first time
            var tenant       = new DnnTenant(PortalSettings.Current);
            var tenantZoneId = Env.ZoneMapper.GetZoneId(tenant);
            var list         = new CmsZones(tenantZoneId, Env, Log).AppsRt.GetSelectableApps(tenant).ToList();

            if (string.IsNullOrWhiteSpace(apps))
            {
                return(list);
            }

            // New feature in 10.27 - if app-list is provided, only return these
            var appNames = apps.Split(',')
                           .Select(s => s.Trim())
                           .Where(s => !string.IsNullOrWhiteSpace(s))
                           .ToList();

            list = list.Where(ap => appNames
                              .Any(name => string.Equals(name, ap.Name, StringComparison.InvariantCultureIgnoreCase)))
                   .ToList();
            return(list);
        }
Beispiel #11
0
        public void Publish(int instanceId, int version)
        {
            Log.Add($"Publish(m:{instanceId}, v:{version})");
            try
            {
                // publish all entites of this content block
                var dnnModule    = ModuleController.Instance.GetModule(instanceId, Null.NullInteger, true);
                var instanceInfo = new DnnContainer(dnnModule);
                // must find tenant through module, as the PortalSettings.Current is null in search mode
                var tenant = new DnnTenant(new PortalSettings(dnnModule.OwnerPortalID));
                var cb     = new BlockFromModule(instanceInfo, Log, tenant);

                Log.Add($"found dnn mod {instanceInfo.Id}, tenant {tenant.Id}, cb exists: {cb.ContentGroupExists}");
                if (cb.ContentGroupExists)
                {
                    Log.Add("cb exists");
                    var appManager = new AppManager(cb /*.AppId*/, Log);

                    // Add content entities
                    IEnumerable <IEntity> list = new List <IEntity>();
                    list = TryToAddStream(list, cb.Data, Constants.DefaultStreamName);
                    list = TryToAddStream(list, cb.Data, "ListContent");
                    list = TryToAddStream(list, cb.Data, "PartOfPage");

                    // ReSharper disable PossibleMultipleEnumeration
                    // Find related presentation entities
                    var attachedPresItems = list
                                            .Where(e => (e as EntityInBlock)?.Presentation != null)
                                            .Select(e => ((EntityInBlock)e).Presentation);
                    Log.Add($"adding presentation item⋮{attachedPresItems.Count()}");
                    list = list.Concat(attachedPresItems);
                    // ReSharper restore PossibleMultipleEnumeration

                    var ids = list.Where(e => !e.IsPublished).Select(e => e.EntityId).ToList();

                    // publish BlockConfiguration as well - if there already is one
                    if (cb.Configuration != null)
                    {
                        Log.Add($"add group id:{cb.Configuration.Id}");
                        ids.Add(cb.Configuration.Id);
                    }

                    Log.Add(() => $"will publish id⋮{ids.Count} ids:[{ string.Join(",", ids.Select(i => i.ToString()).ToArray()) }]");

                    if (ids.Any())
                    {
                        appManager.Entities.Publish(ids.ToArray());
                    }
                    else
                    {
                        Log.Add("no ids found, won\'t publish items");
                    }
                }

                // Set published version
                new PagePublishing.ModuleVersions(instanceId, Log).PublishLatestVersion();
                Log.Add("publish completed");
            }
            catch (Exception ex)
            {
                DnnLogging.LogToDnn("exception", "publishing", Log, force: true);
                DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
                throw;
            }
        }
Beispiel #12
0
        /// <summary>
        /// Get search info for each dnn module containing 2sxc data
        /// </summary>
        /// <returns></returns>
        public IList <SearchDocument> GetModifiedSearchDocuments(IInstanceInfo instance, DateTime beginDate)
        {
            var searchDocuments = new List <SearchDocument>();
            var dnnModule       = (instance as EnvironmentInstance <ModuleInfo>)?.Original;

            // always log with method, to ensure errors are cought
            Log.Add($"start search for mod#{dnnModule?.ModuleID}");

            History.Add("dnn-search", Log);

            if (dnnModule == null)
            {
                return(searchDocuments);
            }

            var isContentModule = dnnModule.DesktopModule.ModuleName == "2sxc";

            // New Context because PortalSettings.Current is null
            var zoneId = new DnnEnvironment(Log).ZoneMapper.GetZoneId(dnnModule.OwnerPortalID);

            var appId = !isContentModule
                ? new DnnMapAppToInstance(Log).GetAppIdFromInstance(instance, zoneId)
                : new ZoneRuntime(zoneId, Log).DefaultAppId;

            if (!appId.HasValue)
            {
                return(searchDocuments);
            }

            // As PortalSettings.Current is null, instanciate with modules' portal id
            var portalSettings = new PortalSettings(dnnModule.OwnerPortalID);

            // Ensure cache builds up with correct primary language
            var cache = Eav.Factory.Resolve <ICache>();

            ((BaseCache)cache).ZoneId = zoneId;
            ((BaseCache)cache).AppId  = appId.Value;
            cache.PreLoadCache(portalSettings.DefaultLanguage.ToLower());

            // must find tenant through module, as the PortalSettings.Current is null in search mode
            var tenant = new DnnTenant(portalSettings);
            var mcb    = new ModuleContentBlock(instance, Log, tenant);
            var sexy   = mcb.SxcInstance;

            var language = dnnModule.CultureCode;

            var contentGroup = sexy.App.ContentGroupManager.GetInstanceContentGroup(dnnModule.ModuleID, dnnModule.TabID);

            var template = contentGroup.Template;

            // This list will hold all EAV entities to be indexed
            var dataSource = sexy.Data;

            if (template == null)
            {
                return(searchDocuments);
            }

            var engine = EngineFactory.CreateEngine(template);

            engine.Init(template, sexy.App, new DnnInstanceInfo(dnnModule), dataSource, InstancePurposes.IndexingForSearch, sexy, Log);

            // see if data customization inside the cshtml works
            try
            {
                engine.CustomizeData();
            }
            catch (Exception e) // Catch errors here, because of references to Request etc.
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }


            var searchInfoDictionary = new Dictionary <string, List <ISearchInfo> >();

            // Get DNN SearchDocuments from 2Sexy SearchInfos
            foreach (var stream in dataSource.Out.Where(p => p.Key != AppConstants.Presentation && p.Key != AppConstants.ListPresentation))
            {
                var entities       = stream.Value.List;
                var searchInfoList = searchInfoDictionary[stream.Key] = new List <ISearchInfo>();

                searchInfoList.AddRange(entities.Select(entity =>
                {
                    var searchInfo = new SearchInfo
                    {
                        Entity          = entity,
                        Url             = "",
                        Description     = "",
                        Body            = GetJoinedAttributes(entity, language),
                        Title           = entity.Title?[language]?.ToString() ?? "(no title)",
                        ModifiedTimeUtc = (entity.Modified == DateTime.MinValue ? DateTime.Now.Date.AddHours(DateTime.Now.Hour) : entity.Modified).ToUniversalTime(),
                        UniqueKey       = "2sxc-" + dnnModule.ModuleID + "-" + (entity.EntityGuid != new Guid() ? entity.EntityGuid.ToString() : (stream.Key + "-" + entity.EntityId)),
                        IsActive        = true,
                        TabId           = dnnModule.TabID,
                        PortalId        = dnnModule.PortalID
                    };

                    // Take the newest value (from ContentGroupItem and Entity)
                    if (entity is IHasEditingData typed)
                    {
                        var contentGroupItemModifiedUtc = typed.ContentGroupItemModified.ToUniversalTime();
                        searchInfo.ModifiedTimeUtc      = searchInfo.ModifiedTimeUtc > contentGroupItemModifiedUtc
                            ? searchInfo.ModifiedTimeUtc
                            : contentGroupItemModifiedUtc;
                    }

                    return(searchInfo);
                }));
            }

            // check if the cshtml has search customizations
            try
            {
                engine.CustomizeSearch(searchInfoDictionary, new DnnInstanceInfo(dnnModule), beginDate);
            }
            catch (Exception e)
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }

            // reduce load by only keeping recently modified ites
            foreach (var searchInfoList in searchInfoDictionary)
            {
                // Filter by Date - take only SearchDocuments that changed since beginDate
                var searchDocumentsToAdd = searchInfoList.Value.Where(p => p.ModifiedTimeUtc >= beginDate.ToUniversalTime()).Select(p => (SearchDocument)p);

                searchDocuments.AddRange(searchDocumentsToAdd);
            }

            return(searchDocuments);
        }
Beispiel #13
0
        /// <summary>
        /// Get search info for each dnn module containing 2sxc data
        /// </summary>
        /// <returns></returns>
        public IList <SearchDocument> GetModifiedSearchDocuments(IContainer container, DateTime beginDate)
        {
            var searchDocuments = new List <SearchDocument>();
            var dnnModule       = (container as Container <ModuleInfo>)?.UnwrappedContents;

            // always log with method, to ensure errors are caught
            Log.Add($"start search for mod#{dnnModule?.ModuleID}");

            // turn off logging into history by default - the template code can reactivate this if desired
            Log.Preserve = false;

            if (dnnModule == null)
            {
                return(searchDocuments);
            }

            // New Context because Portal-Settings.Current is null
            var appId = container.BlockIdentifier.AppId;

            if (appId == AppConstants.AppIdNotFound || appId == Eav.Constants.NullId)
            {
                return(searchDocuments);
            }

            // Since Portal-Settings.Current is null, instantiate with modules' portal id (which can be a different portal!)
            var portalSettings = new PortalSettings(dnnModule.OwnerPortalID);
            var tenant         = new DnnTenant(portalSettings);

            // Ensure cache builds up with correct primary language
            var cache = State.Cache;

            cache.Load(container.BlockIdentifier, tenant.DefaultLanguage);

            var modBlock = new BlockFromModule().Init(new DnnContext(tenant, container, new DnnUser()), Log);

            var language = dnnModule.CultureCode;

            var view = modBlock.View;

            if (view == null)
            {
                return(searchDocuments);
            }

            // This list will hold all EAV entities to be indexed
            var dataSource = modBlock.Data;

            // 2020-03-12 Try to attach DNN Lookup Providers so query-params like [DateTime:Now] or [Portal:PortalId] will work
            if (dataSource?.Configuration?.LookUps != null)
            {
                Log.Add("Will try to attach dnn providers to DataSource LookUps");
                try
                {
                    var dnnLookUps = GetDnnEngine.GenerateDnnBasedLookupEngine(portalSettings, dnnModule.ModuleID, Log);
                    ((LookUpEngine)dataSource.Configuration.LookUps).Link(dnnLookUps);
                }
                catch (Exception e)
                {
                    Log.Add("Ran into an issue with an error: " + e.Message);
                }
            }


            var engine = EngineFactory.CreateEngine(view);

            engine.Init(modBlock, Purpose.IndexingForSearch, Log);

            // see if data customization inside the cshtml works
            try
            {
                engine.CustomizeData();
            }
            catch (Exception e) // Catch errors here, because of references to Request etc.
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }

            var searchInfoDictionary = new Dictionary <string, List <ISearchItem> >();

            // Get DNN SearchDocuments from 2Sexy SearchInfos
            foreach (var stream in dataSource.Out.Where(p => p.Key != ViewParts.Presentation && p.Key != ViewParts.ListPresentation))
            {
                var entities       = stream.Value.List;
                var searchInfoList = searchInfoDictionary[stream.Key] = new List <ISearchItem>();

                searchInfoList.AddRange(entities.Select(entity =>
                {
                    var searchInfo = new SearchItem
                    {
                        Entity          = entity,
                        Url             = "",
                        Description     = "",
                        Body            = GetJoinedAttributes(entity, language),
                        Title           = entity.Title?[language]?.ToString() ?? "(no title)",
                        ModifiedTimeUtc = (entity.Modified == DateTime.MinValue
                            ? DateTime.Now.Date.AddHours(DateTime.Now.Hour)
                            : entity.Modified).ToUniversalTime(),
                        UniqueKey = "2sxc-" + dnnModule.ModuleID + "-" + (entity.EntityGuid != new Guid() ? entity.EntityGuid.ToString() : (stream.Key + "-" + entity.EntityId)),
                        IsActive  = true,
                        TabId     = dnnModule.TabID,
                        PortalId  = dnnModule.PortalID
                    };

                    return(searchInfo);
                }));
            }

            // check if the cshtml has search customizations
            try
            {
                engine.CustomizeSearch(searchInfoDictionary,
                                       new DnnContainer().Init(dnnModule, Log), beginDate);
            }
            catch (Exception e)
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }

            // add it to insights / history. It will only be preserved, if the inner code ran a Log.Preserve = true;
            History.Add("dnn-search", Log);

            // reduce load by only keeping recently modified items
            foreach (var searchInfoList in searchInfoDictionary)
            {
                // Filter by Date - take only SearchDocuments that changed since beginDate
                var searchDocumentsToAdd = searchInfoList.Value.Where(p => p.ModifiedTimeUtc >= beginDate.ToUniversalTime()).Select(p => (SearchDocument)p);
                searchDocuments.AddRange(searchDocumentsToAdd);
            }

            return(searchDocuments);
        }
Beispiel #14
0
        /// <summary>
        /// Get search info for each dnn module containing 2sxc data
        /// </summary>
        /// <returns></returns>
        public IList <SearchDocument> GetModifiedSearchDocuments(IContainer container, DateTime beginDate)
        {
            var searchDocuments = new List <SearchDocument>();
            var dnnModule       = (container as Container <ModuleInfo>)?.UnwrappedContents;

            // always log with method, to ensure errors are caught
            Log.Add($"start search for mod#{dnnModule?.ModuleID}");

            // turn off logging into history by default - the template code can reactivate this if desired
            Log.Preserve = false;

            if (dnnModule == null)
            {
                return(searchDocuments);
            }

            var isContentModule = dnnModule.DesktopModule.ModuleName == "2sxc";

            // New Context because PortalSettings.Current is null
            var zoneId = new DnnEnvironment(Log).ZoneMapper.GetZoneId(dnnModule.OwnerPortalID);

            var appId = !isContentModule
                ? new DnnMapAppToInstance(Log).GetAppIdFromInstance(container, zoneId)
                : new ZoneRuntime(zoneId, Log).DefaultAppId;

            if (!appId.HasValue)
            {
                return(searchDocuments);
            }

            // As PortalSettings.Current is null, instantiate with modules' portal id
            var portalSettings = new PortalSettings(dnnModule.OwnerPortalID);

            // Ensure cache builds up with correct primary language
            var cache = State.Cache;

            cache.Load(new AppIdentity(zoneId, appId.Value), portalSettings.DefaultLanguage.ToLower());

            // must find tenant through module, as the PortalSettings.Current is null in search mode
            var tenant   = new DnnTenant(portalSettings);
            var mcb      = new BlockFromModule(container, Log, tenant);
            var cmsBlock = mcb.BlockBuilder;

            var language = dnnModule.CultureCode;

            var view = cmsBlock.View;

            if (view == null)
            {
                return(searchDocuments);
            }

            // This list will hold all EAV entities to be indexed
            var dataSource = cmsBlock.Block.Data;

            // 2020-03-12 Try to attach DNN Lookup Providers so query-params like [DateTime:Now] or [Portal:PortalId] will work
            if (dataSource?.Configuration?.LookUps != null)
            {
                Log.Add("Will try to attach dnn providers to DataSource LookUps");
                try
                {
                    //var provider = dataSource.Configuration.LookUps;
                    var dnnLookUps = GetDnnEngine.GenerateDnnBasedLookupEngine(portalSettings, dnnModule.ModuleID, Log);
                    ((LookUpEngine)dataSource.Configuration.LookUps).Link(dnnLookUps);
                    //    .Sources;
                    //Log.Add($"Environment provided {dnnLookUps.Count} sources");
                    //foreach (var prov in dnnLookUps)
                    //    if (!provider.Sources.ContainsKey(prov.Key))
                    //        provider.Sources.Add(prov.Key, prov.Value);
                    //    else
                    //        Log.Add($"Couldn't add source '{prov.Key}', as it already existed");
                }
                catch (Exception e)
                {
                    Log.Add("Ran into an issue with an error: " + e.Message);
                }
            }


            var engine = EngineFactory.CreateEngine(view);

            engine.Init(cmsBlock, Purpose.IndexingForSearch, Log);

            // see if data customization inside the cshtml works
            try
            {
                engine.CustomizeData();
            }
            catch (Exception e) // Catch errors here, because of references to Request etc.
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }

            var searchInfoDictionary = new Dictionary <string, List <ISearchItem> >();

            // Get DNN SearchDocuments from 2Sexy SearchInfos
            foreach (var stream in dataSource.Out.Where(p => p.Key != ViewParts.Presentation && p.Key != ViewParts.ListPresentation))
            {
                var entities       = stream.Value.List;
                var searchInfoList = searchInfoDictionary[stream.Key] = new List <ISearchItem>();

                searchInfoList.AddRange(entities.Select(entity =>
                {
                    var searchInfo = new SearchItem
                    {
                        Entity          = entity,
                        Url             = "",
                        Description     = "",
                        Body            = GetJoinedAttributes(entity, language),
                        Title           = entity.Title?[language]?.ToString() ?? "(no title)",
                        ModifiedTimeUtc = (entity.Modified == DateTime.MinValue
                            ? DateTime.Now.Date.AddHours(DateTime.Now.Hour)
                            : entity.Modified).ToUniversalTime(),
                        UniqueKey = "2sxc-" + dnnModule.ModuleID + "-" + (entity.EntityGuid != new Guid() ? entity.EntityGuid.ToString() : (stream.Key + "-" + entity.EntityId)),
                        IsActive  = true,
                        TabId     = dnnModule.TabID,
                        PortalId  = dnnModule.PortalID
                    };

                    // CodeChange #2020-03-20#ContentGroupItemModified - Delete if no side-effects till June 2020
                    // 2020-03-20 2dm: unclear why this happens - the itm.Modified (above)
                    // is identical with the typed.ContentGroupItemModified
                    // because of this I'll turn the code off for now
                    // I also marked 3 other code bits with the code
                    // Take the newest value (from ContentGroupItem and Entity)
                    //if (entity is IHasEditingData typed)
                    //{
                    //    var contentGroupItemModifiedUtc = typed.ContentGroupItemModified.ToUniversalTime();
                    //    searchInfo.ModifiedTimeUtc = searchInfo.ModifiedTimeUtc > contentGroupItemModifiedUtc
                    //        ? searchInfo.ModifiedTimeUtc
                    //        : contentGroupItemModifiedUtc;
                    //}

                    return(searchInfo);
                }));
            }

            // check if the cshtml has search customizations
            try
            {
                engine.CustomizeSearch(searchInfoDictionary, new DnnContainer(dnnModule), beginDate);
            }
            catch (Exception e)
            {
                Exceptions.LogException(new SearchIndexException(dnnModule, e));
            }

            // add it to insights / history. It will only be preserved, if the inner code ran a Log.Preserve = true;
            History.Add("dnn-search", Log);

            // reduce load by only keeping recently modified ites
            foreach (var searchInfoList in searchInfoDictionary)
            {
                // Filter by Date - take only SearchDocuments that changed since beginDate
                var searchDocumentsToAdd = searchInfoList.Value.Where(p => p.ModifiedTimeUtc >= beginDate.ToUniversalTime()).Select(p => (SearchDocument)p);
                searchDocuments.AddRange(searchDocumentsToAdd);
            }

            return(searchDocuments);
        }