예제 #1
0
        public void InheritedMap()
        {
            var definitions = new MapDefinitionCollection(new IMapDefinition[]
            {
                new MapperDefinition1(),
            });
            var mapper = new UmbracoMapper(definitions);

            var thing3 = new Thing3 {
                Value = "value"
            };
            var thing2 = mapper.Map <Thing3, Thing2>(thing3);

            Assert.IsNotNull(thing2);
            Assert.AreEqual("value", thing2.Value);

            thing2 = mapper.Map <Thing2>(thing3);

            Assert.IsNotNull(thing2);
            Assert.AreEqual("value", thing2.Value);

            thing2 = new Thing2();
            mapper.Map(thing3, thing2);
            Assert.AreEqual("value", thing2.Value);
        }
예제 #2
0
        public void SimpleMap()
        {
            var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
            {
                new MapperDefinition1(),
            });
            var mapper = new UmbracoMapper(definitions, _scopeProvider);

            var thing1 = new Thing1 {
                Value = "value"
            };
            Thing2 thing2 = mapper.Map <Thing1, Thing2>(thing1);

            Assert.IsNotNull(thing2);
            Assert.AreEqual("value", thing2.Value);

            thing2 = mapper.Map <Thing2>(thing1);

            Assert.IsNotNull(thing2);
            Assert.AreEqual("value", thing2.Value);

            thing2 = new Thing2();
            mapper.Map(thing1, thing2);
            Assert.AreEqual("value", thing2.Value);
        }
예제 #3
0
        /// <summary>
        /// Returns a collection of entities for media based on search results
        /// </summary>
        /// <param name="results"></param>
        /// <returns></returns>
        private IEnumerable <SearchResultEntity> MemberFromSearchResults(IEnumerable <ISearchResult> results)
        {
            //add additional data
            foreach (var result in results)
            {
                var m = _mapper.Map <SearchResultEntity>(result);

                //if no icon could be mapped, it will be set to document, so change it to picture
                if (m.Icon == Constants.Icons.DefaultIcon)
                {
                    m.Icon = Constants.Icons.Member;
                }

                if (result.Values.ContainsKey("email") && result.Values["email"] != null)
                {
                    m.AdditionalData["Email"] = result.Values["email"];
                }
                if (result.Values.ContainsKey(UmbracoExamineIndex.NodeKeyFieldName) && result.Values[UmbracoExamineIndex.NodeKeyFieldName] != null)
                {
                    if (Guid.TryParse(result.Values[UmbracoExamineIndex.NodeKeyFieldName], out var key))
                    {
                        m.Key = key;
                    }
                }

                yield return(m);
            }
        }
예제 #4
0
        public IEnumerable <DomainVm> GetDomains()
        {
            var domains = _domainService.GetAll(true);

            if (!domains.Any())
            {
                return(Enumerable.Empty <DomainVm>());
            }

            try
            {
                var result = _umbracoMapper.Map <IEnumerable <DomainVm> >(domains);
                foreach (var domainVm in result)
                {
                    if (domainVm.RootContentId != null)
                    {
                        var content = _contentService.GetById(domainVm.RootContentId.Value);

                        if (content != null)
                        {
                            domainVm.Content = _umbracoMapper.Map <ContentVm>(content);
                        }
                    }
                }
                return(result);
            }
            catch (Exception ex)
            {
                Logger.Error(typeof(DomainController), ex);
            }

            return(Enumerable.Empty <DomainVm>());
        }
예제 #5
0
        public IList <Models.DocumentType> GetAllDocTypes()
        {
            List <Models.DocumentType> docTypes = null;

            IScope scope = null;

            try
            {
                scope = _scopeProvider.CreateScope();

                var dbDocTypes = scope.Database.Fetch <UGraphSchema>();

                if (dbDocTypes != null && dbDocTypes.Any())
                {
                    foreach (var dbDocType in dbDocTypes)
                    {
                        docTypes.Add(_mapper.Map <Models.DocumentType>(dbDocType));
                    }
                }
            }
            catch (Exception ex)
            {
                docTypes = null;
            }
            finally
            {
                scope?.Complete();
                scope?.Dispose();
            }

            return(docTypes);
        }
예제 #6
0
    public void EnumerableMap()
    {
        var definitions = new MapDefinitionCollection(() => new IMapDefinition[] { new MapperDefinition1() });
        var mapper      = new UmbracoMapper(definitions, _scopeProvider);

        var thing1A = new Thing1 {
            Value = "valueA"
        };
        var thing1B = new Thing1 {
            Value = "valueB"
        };

        Thing1[] thing1 = { thing1A, thing1B };
        var      thing2 = mapper.Map <IEnumerable <Thing1>, IEnumerable <Thing2> >(thing1).ToList();

        Assert.IsNotNull(thing2);
        Assert.AreEqual(2, thing2.Count);
        Assert.AreEqual("valueA", thing2[0].Value);
        Assert.AreEqual("valueB", thing2[1].Value);

        thing2 = mapper.Map <IEnumerable <Thing2> >(thing1).ToList();

        Assert.IsNotNull(thing2);
        Assert.AreEqual(2, thing2.Count);
        Assert.AreEqual("valueA", thing2[0].Value);
        Assert.AreEqual("valueB", thing2[1].Value);

        thing2 = mapper.MapEnumerable <Thing1, Thing2>(thing1).ToList();

        Assert.IsNotNull(thing2);
        Assert.AreEqual(2, thing2.Count);
        Assert.AreEqual("valueA", thing2[0].Value);
        Assert.AreEqual("valueB", thing2[1].Value);
    }
예제 #7
0
        /// <summary>
        /// Finds a user
        /// </summary>
        /// <param name="userId"/>
        /// <returns/>
        public async Task <BackOfficeIdentityUser> FindByIdAsync(int userId)
        {
            ThrowIfDisposed();
            var user = _userService.GetUserById(userId);

            if (user == null)
            {
                return(null);
            }

            return(await Task.FromResult(AssignLoginsCallback(_mapper.Map <BackOfficeIdentityUser>(user))));
        }
        public virtual ActionResult Index(HomePage model)
        {
            var contentResponseViewModel = string.Empty.IsApiRequest()
                ? (object)_umbracoMapper.Map <BaseContentSuggestionViewModel>(model)
                : _contentResponseBuilder.BuildContentResponse(_umbracoMapper.Map <BaseContentViewModel>(model), model);

            return(new ContentResult
            {
                Content = JsonConvert.SerializeObject(contentResponseViewModel, _jsonSerializerSettings),
                ContentEncoding = Encoding.UTF8,
                ContentType = ApplicationConstants.ContentTypeApplicationJson
            });
        }
예제 #9
0
        public IEnumerable <ProductSparse> GetAll(string culture = null)
        {
            var productRoot = GetProductRootPage();

            if (productRoot == null)
            {
                throw new EntityNotFoundException(typeof(ProductContentType));
            }

            var children = productRoot
                           .Children <ProductContentType>()
                           .Select(x => _umbracoMapper.Map <ProductSparse>(x));

            return(children);
        }
예제 #10
0
        /// <summary>
        ///     Used to throw the ModelState validation results when the ModelState is invalid
        /// </summary>
        /// <typeparam name="TContentTypeDisplay"></typeparam>
        /// <typeparam name="TContentTypeSave"></typeparam>
        /// <param name="ctId"></param>
        /// <param name="contentTypeSave"></param>
        /// <param name="ct"></param>
        private TContentTypeDisplay?CreateModelStateValidationEror <TContentTypeSave, TContentTypeDisplay>(int ctId,
                                                                                                           TContentTypeSave contentTypeSave, TContentType?ct)
            where TContentTypeDisplay : ContentTypeCompositionDisplay
            where TContentTypeSave : ContentTypeSave
        {
            TContentTypeDisplay?forDisplay;

            if (ctId > 0)
            {
                //Required data is invalid so we cannot continue
                forDisplay = UmbracoMapper.Map <TContentTypeDisplay>(ct);
                //map the 'save' data on top
                forDisplay = UmbracoMapper.Map(contentTypeSave, forDisplay);
            }
            else
            {
                //map the 'save' data to display
                forDisplay = UmbracoMapper.Map <TContentTypeDisplay>(contentTypeSave);
            }

            if (forDisplay is not null)
            {
                forDisplay.Errors = ModelState.ToErrorDictionary();
            }

            return(forDisplay);
        }
예제 #11
0
        /// <summary>
        ///     Validates the composition and adds errors to the model state if any are found then throws an error response if
        ///     there are errors
        /// </summary>
        /// <param name="contentTypeSave"></param>
        /// <param name="composition"></param>
        /// <returns></returns>
        private TContentTypeDisplay?CreateCompositionValidationExceptionIfInvalid <TContentTypeSave, TPropertyType,
                                                                                   TContentTypeDisplay>(TContentTypeSave contentTypeSave, TContentType?composition)
            where TContentTypeSave : ContentTypeSave <TPropertyType>
            where TPropertyType : PropertyTypeBasic
            where TContentTypeDisplay : ContentTypeCompositionDisplay
        {
            IContentTypeBaseService <TContentType>?service = GetContentTypeService <TContentType>();
            Attempt <string[]?> validateAttempt            = service?.ValidateComposition(composition) ?? Attempt.Fail <string[]?>();

            if (validateAttempt == false)
            {
                // if it's not successful then we need to return some model state for the property type and property group
                // aliases that are duplicated
                IEnumerable <string>?duplicatePropertyTypeAliases = validateAttempt.Result?.Distinct();
                var invalidPropertyGroupAliases =
                    (validateAttempt.Exception as InvalidCompositionException)?.PropertyGroupAliases ??
                    Array.Empty <string>();

                AddCompositionValidationErrors <TContentTypeSave, TPropertyType>(contentTypeSave,
                                                                                 duplicatePropertyTypeAliases, invalidPropertyGroupAliases);

                TContentTypeDisplay?display = UmbracoMapper.Map <TContentTypeDisplay>(composition);
                //map the 'save' data on top
                display = UmbracoMapper.Map(contentTypeSave, display);
                if (display is not null)
                {
                    display.Errors = ModelState.ToErrorDictionary();
                }

                return(display);
            }

            return(null);
        }
예제 #12
0
    public void CollectionsMap()
    {
        var definitions = new MapDefinitionCollection(() => new IMapDefinition[] { new MapperDefinition2() });
        var mapper      = new UmbracoMapper(definitions, _scopeProvider);

        // can map a PropertyCollection
        var source = new PropertyCollection();
        var target = mapper.Map <IEnumerable <ContentPropertyDto> >(source);
    }
예제 #13
0
    public void NullPropertyMap()
    {
        var definitions = new MapDefinitionCollection(() => new IMapDefinition[] { new MapperDefinition5() });
        var mapper      = new UmbracoMapper(definitions, _scopeProvider);

        var thing7 = new Thing7();

        var thing8 = mapper.Map <Thing7, Thing8>(thing7);

        Assert.IsNotNull(thing8);
        Assert.IsNull(thing8.Things);
    }
예제 #14
0
        /// <summary>
        /// Maps a menu item from a content node
        /// </summary>
        /// <param name="item">Content node to map from</param>
        /// <returns></returns>
        private MenuItemViewModel MapItem(IPublishedContent item)
        {
            MenuItemViewModel model = null;

            if (item != null)
            {
                model = new MenuItemViewModel();
                UmbracoMapper.Map(item, model);
                model.IsCurrentPage           = CurrentPage.Id.Equals(item.Id);
                model.IsCurrentPageOrAncestor = CurrentPage.Path.Contains(item.Id.ToString());
            }

            return(model);
        }
예제 #15
0
    public void EnumMap()
    {
        var definitions = new MapDefinitionCollection(() => new IMapDefinition[] { new MapperDefinition4() });
        var mapper      = new UmbracoMapper(definitions, _scopeProvider);

        var thing5 = new Thing5 {
            Fruit1 = Thing5Enum.Apple, Fruit2 = Thing5Enum.Banana, Fruit3 = Thing5Enum.Cherry
        };

        var thing6 = mapper.Map <Thing5, Thing6>(thing5);

        Assert.IsNotNull(thing6);
        Assert.AreEqual(Thing6Enum.Apple, thing6.Fruit1);
        Assert.AreEqual(Thing6Enum.Banana, thing6.Fruit2);
        Assert.AreEqual(Thing6Enum.Cherry, thing6.Fruit3);
    }
        public void Save(List <EnterspeedJob> jobs)
        {
            if (jobs == null || !jobs.Any())
            {
                return;
            }

            using (var scope = _scopeProvider.CreateScope(autoComplete: true))
            {
                foreach (var job in jobs)
                {
                    var jobToSave = _mapper.Map <EnterspeedJobSchema>(job);
                    scope.Database.Save(jobToSave);
                    job.Id = jobToSave.Id;
                }
            }
        }
        /// <summary>
        /// Validates the composition and adds errors to the model state if any are found then throws an error response if there are errors
        /// </summary>
        /// <param name="contentTypeSave"></param>
        /// <param name="composition"></param>
        /// <returns></returns>
        private TContentTypeDisplay CreateCompositionValidationExceptionIfInvalid <TContentTypeSave, TPropertyType, TContentTypeDisplay>(TContentTypeSave contentTypeSave, TContentType composition)
            where TContentTypeSave : ContentTypeSave <TPropertyType>
            where TPropertyType : PropertyTypeBasic
            where TContentTypeDisplay : ContentTypeCompositionDisplay
        {
            var service         = GetContentTypeService <TContentType>();
            var validateAttempt = service.ValidateComposition(composition);

            if (validateAttempt == false)
            {
                //if it's not successful then we need to return some model state for the property aliases that
                // are duplicated
                var invalidPropertyAliases = validateAttempt.Result.Distinct();
                AddCompositionValidationErrors <TContentTypeSave, TPropertyType>(contentTypeSave, invalidPropertyAliases);

                var display = UmbracoMapper.Map <TContentTypeDisplay>(composition);
                //map the 'save' data on top
                display        = UmbracoMapper.Map(contentTypeSave, display);
                display.Errors = ModelState.ToErrorDictionary();
                return(display);
            }
            return(null);
        }
예제 #18
0
    public void ConcurrentMap()
    {
        var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
        {
            new MapperDefinition1(),
            new MapperDefinition3(),
        });
        var mapper = new UmbracoMapper(definitions, _scopeProvider);

        // the mapper currently has a map from Thing1 to Thing2
        // because Thing3 inherits from Thing1, it will map a Thing3 instance,
        // and register a new map from Thing3 to Thing2,
        // thus modifying its internal dictionaries

        // if timing is good, and mapper does have non-concurrent dictionaries, it fails
        // practically, to reproduce, one needs to add a 1s sleep in the mapper's loop
        // hence, this test is explicit
        var thing3 = new Thing3 {
            Value = "value"
        };
        var       thing4 = new Thing4();
        Exception caught = null;

        void ThreadLoop()
        {
            // keep failing at mapping - and looping through the maps
            for (var i = 0; i < 10; i++)
            {
                try
                {
                    mapper.Map <Thing2>(thing4);
                }
                catch (Exception e)
                {
                    caught = e;
                    Console.WriteLine($"{e.GetType().Name} {e.Message}");
                }
            }

            Console.WriteLine("done");
        }

        var thread = new Thread(ThreadLoop);

        thread.Start();
        Thread.Sleep(1000);

        try
        {
            Console.WriteLine($"{DateTime.Now:O} mapping");
            var thing2 = mapper.Map <Thing2>(thing3);
            Console.WriteLine($"{DateTime.Now:O} mapped");

            Assert.IsNotNull(thing2);
            Assert.AreEqual("value", thing2.Value);
        }
        finally
        {
            thread.Join();
        }
    }
예제 #19
0
            public void DefineMaps(UmbracoMapper mapper)
            {
                mapper.Define <ProductPage, Product>(
                    ctor: (source, context) => new Product(),
                    map: (source, target, context) =>
                {
                    target.Id               = source.Key.ToString();
                    target.Name             = source.Name;
                    target.ArticleNumber    = source.ArticleNumber;
                    target.Description      = source.ProductDescription;
                    target.Price            = source.Price;
                    target.RecommendedPrice = source.RecommendedPrice;
                    target.ImageUrls        = source.ProductImages.Select(i => i.Url());
                    target.Url              = source.Url();
                    target.Categories       = source.Categories.Select(c => c.Name);
                }
                    );

                mapper.Define <CategoryPage, Category>(
                    ctor: (source, context) => new Category(),
                    map: (source, target, context) =>
                {
                    target.Name           = source.Name;
                    target.ImageUrl       = source.HeroImage?.Url();
                    target.Url            = source.Url();
                    target.IsSaleCategory = source.IsSaleCategory;
                }
                    );

                mapper.Define <Umbraco.Web.PublishedModels.HomePage, Models.HomePage>(
                    ctor: (source, context) => new Models.HomePage(),
                    map: (source, target, context) =>
                {
                    target.CompanyName   = source.CompanyName;
                    target.CompanySlogan = source.CompanySlogan;
                    target.HeroImageUrl  = source.HeroImage?.Url();

                    target.TrendingHeader       = source.TrendingHeader;
                    target.TrendingHeaderBgText = string.IsNullOrWhiteSpace(source.TrendingHeaderBackground) ? source.TrendingHeader : source.TrendingHeaderBackground;
                    target.TrendingProducts     = source.TrendingProducts.Select(p => mapper.Map <Product>(new ProductPage(p)));

                    target.LinksHeader       = source.LinksHeader;
                    target.LinksHeaderBgText = string.IsNullOrWhiteSpace(source.LinksHeaderBackground) ? source.LinksHeader : source.LinksHeaderBackground;
                    target.CategoryLinks     = source.CategoryLinks.Select(c => mapper.Map <Category>(new CategoryPage(c)));

                    target.CampaignHeader       = source.CampaignHeader;
                    target.CampaignHeaderBgText = string.IsNullOrWhiteSpace(source.CampaignHeaderBackground) ? source.CampaignHeader : source.CampaignHeaderBackground;
                    target.CampaignName         = source.CampaignTitle;
                    target.CampaignImageUrl     = source.CampaignImage?.Url();
                }
                    );

                mapper.Define <Umbraco.Web.PublishedModels.FooterElement, Models.FooterElement>(
                    ctor: (source, context) => new Models.FooterElement(),
                    map: (source, target, context) =>
                {
                    target.IconName = source.IconName;
                    target.Text     = source.Text;
                }
                    );
            }
예제 #20
0
        private EntityBasic GetEntity(int nodeId)
        {
            var entity = _entityService.Get(nodeId);

            return(entity != null?_mapper.Map <IEntitySlim, EntityBasic>(entity) : null);
        }
예제 #21
0
        protected ActionResult <TContentType?> PerformPostSave <TContentTypeDisplay, TContentTypeSave, TPropertyType>(
            TContentTypeSave contentTypeSave,
            Func <int, TContentType?> getContentType,
            Action <TContentType?> saveContentType,
            Action <TContentTypeSave>?beforeCreateNew = null)
            where TContentTypeDisplay : ContentTypeCompositionDisplay
            where TContentTypeSave : ContentTypeSave <TPropertyType>
            where TPropertyType : PropertyTypeBasic
        {
            var          ctId = Convert.ToInt32(contentTypeSave.Id);
            TContentType?ct   = ctId > 0 ? getContentType(ctId) : null;

            if (ctId > 0 && ct == null)
            {
                return(NotFound());
            }

            //Validate that there's no other ct with the same alias
            // it in fact cannot be the same as any content type alias (member, content or media) because
            // this would interfere with how ModelsBuilder works and also how many of the published caches
            // works since that is based on aliases.
            IEnumerable <string> allAliases = ContentTypeService.GetAllContentTypeAliases();
            var exists = allAliases.InvariantContains(contentTypeSave.Alias);

            if (exists && (ctId == 0 || (!ct?.Alias.InvariantEquals(contentTypeSave.Alias) ?? false)))
            {
                ModelState.AddModelError("Alias",
                                         LocalizedTextService.Localize("editcontenttype", "aliasAlreadyExists"));
            }

            // execute the external validators
            ValidateExternalValidators(ModelState, contentTypeSave);

            if (ModelState.IsValid == false)
            {
                TContentTypeDisplay?err =
                    CreateModelStateValidationEror <TContentTypeSave, TContentTypeDisplay>(ctId, contentTypeSave, ct);
                return(ValidationProblem(err));
            }

            //filter out empty properties
            contentTypeSave.Groups = contentTypeSave.Groups.Where(x => x.Name.IsNullOrWhiteSpace() == false).ToList();
            foreach (PropertyGroupBasic <TPropertyType> group in contentTypeSave.Groups)
            {
                group.Properties = group.Properties.Where(x => x.Alias.IsNullOrWhiteSpace() == false).ToList();
            }

            if (ctId > 0)
            {
                //its an update to an existing content type

                //This mapping will cause a lot of content type validation to occur which we need to deal with
                try
                {
                    UmbracoMapper.Map(contentTypeSave, ct);
                }
                catch (Exception ex)
                {
                    TContentTypeDisplay?responseEx =
                        CreateInvalidCompositionResponseException <TContentTypeDisplay, TContentTypeSave, TPropertyType>(
                            ex, contentTypeSave, ct, ctId);
                    if (responseEx != null)
                    {
                        return(ValidationProblem(responseEx));
                    }
                }

                TContentTypeDisplay?exResult =
                    CreateCompositionValidationExceptionIfInvalid <TContentTypeSave, TPropertyType, TContentTypeDisplay>(
                        contentTypeSave, ct);
                if (exResult != null)
                {
                    return(ValidationProblem(exResult));
                }

                saveContentType(ct);

                return(ct);
            }
            else
            {
                if (beforeCreateNew != null)
                {
                    beforeCreateNew(contentTypeSave);
                }

                //check if the type is trying to allow type 0 below itself - id zero refers to the currently unsaved type
                //always filter these 0 types out
                var allowItselfAsChild          = false;
                var allowIfselfAsChildSortOrder = -1;
                if (contentTypeSave.AllowedContentTypes != null)
                {
                    allowIfselfAsChildSortOrder = contentTypeSave.AllowedContentTypes.IndexOf(0);
                    allowItselfAsChild          = contentTypeSave.AllowedContentTypes.Any(x => x == 0);

                    contentTypeSave.AllowedContentTypes =
                        contentTypeSave.AllowedContentTypes.Where(x => x > 0).ToList();
                }

                //save as new

                TContentType?newCt = null;
                try
                {
                    //This mapping will cause a lot of content type validation to occur which we need to deal with
                    newCt = UmbracoMapper.Map <TContentType>(contentTypeSave);
                }
                catch (Exception ex)
                {
                    TContentTypeDisplay?responseEx =
                        CreateInvalidCompositionResponseException <TContentTypeDisplay, TContentTypeSave, TPropertyType>(
                            ex, contentTypeSave, ct, ctId);
                    if (responseEx is null)
                    {
                        throw ex;
                    }

                    return(ValidationProblem(responseEx));
                }

                TContentTypeDisplay?exResult =
                    CreateCompositionValidationExceptionIfInvalid <TContentTypeSave, TPropertyType, TContentTypeDisplay>(
                        contentTypeSave, newCt);
                if (exResult != null)
                {
                    return(ValidationProblem(exResult));
                }

                //set id to null to ensure its handled as a new type
                contentTypeSave.Id         = null;
                contentTypeSave.CreateDate = DateTime.Now;
                contentTypeSave.UpdateDate = DateTime.Now;

                saveContentType(newCt);

                //we need to save it twice to allow itself under itself.
                if (allowItselfAsChild && newCt != null)
                {
                    newCt.AllowedContentTypes =
                        newCt.AllowedContentTypes?.Union(
                            new[] { new ContentTypeSort(newCt.Id, allowIfselfAsChildSortOrder) }
                            );
                    saveContentType(newCt);
                }

                return(newCt);
            }
        }
예제 #22
0
        /// <summary>
        ///     Returns the available composite content types for a given content type
        /// </summary>
        /// <param name="type"></param>
        /// <param name="filterContentTypes">
        ///     This is normally an empty list but if additional content type aliases are passed in, any content types containing
        ///     those aliases will be filtered out
        ///     along with any content types that have matching property types that are included in the filtered content types
        /// </param>
        /// <param name="filterPropertyTypes">
        ///     This is normally an empty list but if additional property type aliases are passed in, any content types that have
        ///     these aliases will be filtered out.
        ///     This is required because in the case of creating/modifying a content type because new property types being added to
        ///     it are not yet persisted so cannot
        ///     be looked up via the db, they need to be passed in.
        /// </param>
        /// <param name="contentTypeId"></param>
        /// <param name="isElement">Whether the composite content types should be applicable for an element type</param>
        /// <returns></returns>
        protected ActionResult <IEnumerable <Tuple <EntityBasic?, bool> > > PerformGetAvailableCompositeContentTypes(
            int contentTypeId,
            UmbracoObjectTypes type,
            string[]?filterContentTypes,
            string[]?filterPropertyTypes,
            bool isElement)
        {
            IContentTypeComposition?source = null;

            //below is all ported from the old doc type editor and comes with the same weaknesses /insanity / magic

            IContentTypeComposition[] allContentTypes;

            switch (type)
            {
            case UmbracoObjectTypes.DocumentType:
                if (contentTypeId > 0)
                {
                    source = ContentTypeService.Get(contentTypeId);
                    if (source == null)
                    {
                        return(NotFound());
                    }
                }

                allContentTypes = ContentTypeService.GetAll().Cast <IContentTypeComposition>().ToArray();
                break;

            case UmbracoObjectTypes.MediaType:
                if (contentTypeId > 0)
                {
                    source = MediaTypeService.Get(contentTypeId);
                    if (source == null)
                    {
                        return(NotFound());
                    }
                }

                allContentTypes = MediaTypeService.GetAll().Cast <IContentTypeComposition>().ToArray();
                break;

            case UmbracoObjectTypes.MemberType:
                if (contentTypeId > 0)
                {
                    source = MemberTypeService.Get(contentTypeId);
                    if (source == null)
                    {
                        return(NotFound());
                    }
                }

                allContentTypes = MemberTypeService.GetAll().Cast <IContentTypeComposition>().ToArray();
                break;

            default:
                throw new ArgumentOutOfRangeException("The entity type was not a content type");
            }

            ContentTypeAvailableCompositionsResults availableCompositions =
                ContentTypeService.GetAvailableCompositeContentTypes(source, allContentTypes, filterContentTypes,
                                                                     filterPropertyTypes, isElement);


            IContentTypeComposition[] currCompositions =
                source == null ? new IContentTypeComposition[] { } : source.ContentTypeComposition.ToArray();
            var compAliases = currCompositions.Select(x => x.Alias).ToArray();
            IEnumerable <string> ancestors = availableCompositions.Ancestors.Select(x => x.Alias);

            return(availableCompositions.Results
                   .Select(x =>
                           new Tuple <EntityBasic?, bool>(UmbracoMapper.Map <IContentTypeComposition, EntityBasic>(x.Composition),
                                                          x.Allowed))
                   .Select(x =>
            {
                //we need to ensure that the item is enabled if it is already selected
                // but do not allow it if it is any of the ancestors
                if (compAliases.Contains(x.Item1?.Alias) && ancestors.Contains(x.Item1?.Alias) == false)
                {
                    //re-set x to be allowed (NOTE: I didn't know you could set an enumerable item in a lambda!)
                    x = new Tuple <EntityBasic?, bool>(x.Item1, true);
                }

                //translate the name
                if (x.Item1 is not null)
                {
                    x.Item1.Name = TranslateItem(x.Item1.Name);
                }

                IContentTypeComposition?contentType = allContentTypes.FirstOrDefault(c => c.Key == x.Item1?.Key);
                EntityContainer[] containers = GetEntityContainers(contentType, type).ToArray();
                var containerPath =
                    $"/{(containers.Any() ? $"{string.Join("/", containers.Select(c => c.Name))}/" : null)}";
                if (x.Item1 is not null)
                {
                    x.Item1.AdditionalData["containerPath"] = containerPath;
                }

                return x;
            })
                   .ToList());
        }