public ArchiveModel GetArchiveSubTree(int siteId, int itemId)
        {
            _logger.LogTrace($"GetArchiveSubStructure siteId={siteId}, itemId={itemId}");
            var useRegion = _settingsProvider.HasRegion(siteId);
            var iconUrl   = _settingsProvider.GetIconUrl(siteId);

            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var abstractItems = _siteMapProvider.GetAllItems(siteId, true, useRegion);

            // abstractItems.ForEach(x => x.IconUrl = $"{iconUrl}/{x.IconUrl}");
            stopwatch.Stop();
            _logger.LogTrace($"get all archive abstract items {stopwatch.ElapsedMilliseconds}ms");

            stopwatch.Reset();
            stopwatch.Start();

            var archives = _mapper.Map <List <ArchiveModel> >(abstractItems).OrderBy(x => x.IndexOrder).ToList();

            var result = SiteMapStructureBuilder.GetArchiveSubTree(itemId, archives);

            stopwatch.Stop();
            _logger.LogTrace($"convert archive abstract items to tree {stopwatch.ElapsedMilliseconds}ms");

            return(result.FirstOrDefault());
        }
        public PageModel GetSiteMapSubTree(int siteId, int itemId, int[] regionIds = null, bool?useHierarchyRegionFilter = null)
        {
            _logger.LogTrace($"GetSiteMapSubStructure siteId={siteId}, regionIds={string.Join(", ", regionIds)}, useHierarchyRegionFilter={useHierarchyRegionFilter}");
            Func <AbstractItemData, bool> regionFilter = x => true;
            var useRegion = _settingsProvider.HasRegion(siteId);

            if (useRegion)
            {
                _logger.LogTrace("Use region filter");
                var rootPage = _siteMapProvider.GetRootPage(siteId);
                var regions  = _dictionaryProvider.GetAllRegions(siteId);
                var filter   = RegionFilterFactory.Create(rootPage, regions, useHierarchyRegionFilter ?? false);
                regionFilter = filter.GetFilter(regionIds);
            }

            var iconUrl = _settingsProvider.GetIconUrl(siteId);

            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var abstractItems = _siteMapProvider.GetAllItems(siteId, false, useRegion)
                                .Where(regionFilter)
                                .ToList();

            // abstractItems.ForEach(x => x.IconUrl = $"{iconUrl}/{x.IconUrl}");
            stopwatch.Stop();
            _logger.LogTrace($"get all abstract items {stopwatch.ElapsedMilliseconds}ms");

            stopwatch.Reset();
            stopwatch.Start();

            var pages   = abstractItems.Where(x => x.IsPage).Select(x => _mapper.Map <PageModel>(x)).OrderBy(x => x.IndexOrder).ToList();
            var widgets = abstractItems.Where(x => !x.IsPage).Select(x => _mapper.Map <WidgetModel>(x)).OrderBy(x => x.IndexOrder).ToList();

            var result = SiteMapStructureBuilder.GetPageSubTree(itemId, pages, widgets);

            stopwatch.Stop();
            _logger.LogTrace($"convert abstract items to tree {stopwatch.ElapsedMilliseconds}ms");

            return(result.FirstOrDefault());
        }
        public void DeleteSiteMapItems(
            int siteId, int userId, int itemId,
            bool isDeleteAllVersions)
        {
            if (itemId <= 0)
            {
                throw new ArgumentException("itemId <= 0");
            }

            var item = _siteMapProvider.GetByIds(siteId, true, new[] { itemId })?.FirstOrDefault();

            if (item == null || item.Id == 0)
            {
                throw new InvalidOperationException($"Element {itemId} not found");
            }

            var rootPageId = _siteMapProvider.GetRootPage(siteId)?.Id;

            if (itemId == rootPageId)
            {
                throw new InvalidOperationException("Cannot delete the root page");
            }

            var itemsToDelete = new List <AbstractItemData>();

            var allItems        = _siteMapProvider.GetAllItems(siteId, true, false);
            var pages           = allItems.Where(x => x.IsPage).Select(x => _mapper.Map <PageModel>(x)).OrderBy(x => x.IndexOrder).ToList();
            var widgets         = allItems.Where(x => !x.IsPage).Select(x => _mapper.Map <WidgetModel>(x)).OrderBy(x => x.IndexOrder).ToList();
            var pageStructure   = item.IsPage ? SiteMapStructureBuilder.GetPageSubTree(itemId, pages, widgets) : new List <PageModel>();
            var widgetStructure = !item.IsPage ? SiteMapStructureBuilder.GetWidgetSubTree(itemId, widgets) : new List <WidgetModel>();

            void funcWidgets(List <WidgetModel> items)
            {
                foreach (var i in items)
                {
                    itemsToDelete.AddRange(allItems.Where(x => x.Id == i.Id));

                    if (i.HasChildren)
                    {
                        funcWidgets(i.Children);
                    }
                }
            }

            void func(List <PageModel> items)
            {
                foreach (var i in items)
                {
                    itemsToDelete.AddRange(allItems.Where(x => x.Id == i.Id));

                    if (i.HasContentVersion)
                    {
                        itemsToDelete.AddRange(allItems.Where(x => i.ContentVersions.Any(y => x.Id == y.Id)));
                    }

                    if (i.HasWidgets)
                    {
                        funcWidgets(i.Widgets);
                    }

                    if (i.HasChildren)
                    {
                        func(i.Children);
                    }
                }
            }

            if (isDeleteAllVersions)
            {
                var structuralVersions = allItems.Where(x => x.ParentId == item.ParentId && x.Alias == item.Alias && x.Id != item.Id).ToList();
                foreach (var structuralVersion in structuralVersions)
                {
                    if (!structuralVersion.IsPage)
                    {
                        continue;
                    }
                    var structuralVersionPageStructure = SiteMapStructureBuilder.GetPageSubTree(structuralVersion.Id, pages, widgets);
                    func(structuralVersionPageStructure);
                }
            }

            func(pageStructure);
            funcWidgets(widgetStructure);

            var contentId = _settingsProvider.GetContentId(siteId);

            if (itemsToDelete.Any())
            {
                _qpDataProvider.Delete(siteId, contentId, userId, itemsToDelete);
            }
        }
        public void RemoveSiteMapItems(
            int siteId, int userId, int itemId,
            bool isDeleteAllVersions, bool isDeleteContentVersion, int?contentVersionId)
        {
            if (itemId <= 0)
            {
                throw new ArgumentException("itemId <= 0");
            }
            if (!isDeleteContentVersion && contentVersionId == null)
            {
                throw new InvalidOperationException("Field contentVersionId is required if isDeleteContentVersion is false");
            }

            var item = _siteMapProvider.GetByIds(siteId, false, new[] { itemId })?.FirstOrDefault();

            if (item == null || item.Id == 0)
            {
                throw new InvalidOperationException($"Element {itemId} not found");
            }

            if (contentVersionId.HasValue)
            {
                var contentVersion = _siteMapProvider.GetByIds(siteId, false, new[] { contentVersionId.Value })?.FirstOrDefault();
                if (contentVersion == null || contentVersion.Id == 0)
                {
                    throw new InvalidOperationException($"Element {contentVersionId} not found");
                }
            }

            var rootPageId = _siteMapProvider.GetRootPage(siteId)?.Id;

            if (itemId == rootPageId)
            {
                throw new InvalidOperationException("Cannot delete the root page");
            }

            var itemsToArchive = new List <AbstractItemData>();
            AbstractItemData moveContentVersion = null;

            var allItems        = _siteMapProvider.GetAllItems(siteId, false, false);
            var pages           = allItems.Where(x => x.IsPage).Select(x => _mapper.Map <PageModel>(x)).OrderBy(x => x.IndexOrder).ToList();
            var widgets         = allItems.Where(x => !x.IsPage).Select(x => _mapper.Map <WidgetModel>(x)).OrderBy(x => x.IndexOrder).ToList();
            var pageStructure   = item.IsPage ? SiteMapStructureBuilder.GetPageSubTree(itemId, pages, widgets) : new List <PageModel>();
            var widgetStructure = !item.IsPage ? SiteMapStructureBuilder.GetWidgetSubTree(itemId, widgets) : new List <WidgetModel>();

            void funcWidgets(List <WidgetModel> items)
            {
                foreach (var i in items)
                {
                    itemsToArchive.AddRange(allItems.Where(x => x.Id == i.Id));

                    if (i.HasChildren)
                    {
                        funcWidgets(i.Children);
                    }
                }
            }

            void func(List <PageModel> items)
            {
                foreach (var i in items)
                {
                    itemsToArchive.AddRange(allItems.Where(x => x.Id == i.Id));

                    if (!isDeleteAllVersions & !isDeleteContentVersion)
                    {
                        moveContentVersion = allItems.FirstOrDefault(x => x.Id == contentVersionId);
                        if (moveContentVersion != null && moveContentVersion.VersionOfId != null)
                        {
                            moveContentVersion.Alias       = item.Alias;
                            moveContentVersion.ParentId    = item.ParentId;
                            moveContentVersion.VersionOfId = null;
                        }
                    }
                    else
                    {
                        if (i.HasContentVersion)
                        {
                            itemsToArchive.AddRange(allItems.Where(x => i.ContentVersions.Any(y => x.Id == y.Id)));
                        }
                    }

                    if (i.HasWidgets)
                    {
                        funcWidgets(i.Widgets);
                    }

                    if (i.HasChildren)
                    {
                        func(i.Children);
                    }
                }
            }

            if (isDeleteAllVersions)
            {
                var structuralVersions = allItems.Where(x => x.ParentId == item.ParentId && x.Alias == item.Alias && x.Id != item.Id).ToList();
                foreach (var structuralVersion in structuralVersions)
                {
                    if (!structuralVersion.IsPage)
                    {
                        continue;
                    }
                    var structuralVersionPageStructure = SiteMapStructureBuilder.GetPageSubTree(structuralVersion.Id, pages, widgets);
                    func(structuralVersionPageStructure);
                }
            }

            func(pageStructure);
            funcWidgets(widgetStructure);

            var contentId = _settingsProvider.GetContentId(siteId);

            _qpDataProvider.Remove(siteId, contentId, userId, itemsToArchive, moveContentVersion);
        }