예제 #1
0
        public void SaveRelations(ContentRelationsDto contentRelations)
        {
            if (contentRelations.Sets == null || !contentRelations.Sets.Any())
            {
                return;
            }

            var relations    = relationService.GetByParentId(contentRelations.ParentId).ToList();
            var parentEntity = entityService.Get(contentRelations.ParentId, contentRelations.ParentType);

            foreach (var set in contentRelations.Sets)
            {
                var typeId       = set.RelationTypeId;
                var type         = relationService.GetRelationTypeById(set.RelationTypeId);
                var setRelations = relations.Where(r => r.RelationTypeId == typeId);
                foreach (var removeRelation in setRelations)
                {
                    relationService.Delete(removeRelation);
                }

                foreach (var relation in set.Relations)
                {
                    if (relation.State == RelationStateEnum.Deleted || relation.Readonly)
                    {
                        continue;
                    }

                    var childEntity = entityService.Get(relation.ChildId, UmbracoObjectTypesExtensions.GetUmbracoObjectType(type.ChildObjectType));
                    relationService.Relate(parentEntity, childEntity, type);
                }
            }
        }
예제 #2
0
        protected TreeNode GetSingleTreeNode(string id, FormDataCollection queryStrings)
        {
            if (_isUmbracoProvider)
            {
                Guid asGuid;
                if (Guid.TryParse(id, out asGuid) == false)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                }

                var member = Services.MemberService.GetByKey(asGuid);
                if (member == null)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                }

                var node = CreateTreeNode(
                    member.Key.ToString("N"),
                    "-1",
                    queryStrings,
                    member.Name,
                    "icon-user",
                    false,
                    "",
                    Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(Constants.ObjectTypes.MemberGuid), member.Key));

                node.AdditionalData.Add("contentType", member.ContentTypeAlias);
                node.AdditionalData.Add("isContainer", true);

                return node;
            }
            else
            {
                object providerId = id;
                Guid asGuid;
                if (Guid.TryParse(id, out asGuid))
                {
                    providerId = asGuid;
                }

                var member = _provider.GetUser(providerId, false);
                if (member == null)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                }

                var node = CreateTreeNode(
                    member.ProviderUserKey.TryConvertTo<Guid>().Result.ToString("N"),
                    "-1",
                    queryStrings,
                    member.UserName,
                    "icon-user",
                    false);

                return node;    
            }

            
        }
        /// <summary>
        /// Helper method to create tree nodes and automatically generate the json url + UDI
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="entityObjectType"></param>
        /// <param name="parentId"></param>
        /// <param name="queryStrings"></param>
        /// <param name="icon"></param>
        /// <param name="hasChildren"></param>
        /// <returns></returns>
        public TreeNode CreateTreeNode(IUmbracoEntity entity, Guid entityObjectType, string parentId, FormDataCollection queryStrings, string icon, bool hasChildren)
        {
            var treeNode = CreateTreeNode(entity.Id.ToInvariantString(), parentId, queryStrings, entity.Name, icon);

            treeNode.Udi         = Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(entityObjectType), entity.Key);
            treeNode.HasChildren = hasChildren;
            return(treeNode);
        }
예제 #4
0
 /// <summary>
 /// Gets the Parent objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
 /// </summary>
 /// <param name="relations">List of relations to retrieve parent objects from</param>
 /// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
 public IEnumerable <IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable <IRelation> relations)
 {
     foreach (var relation in relations)
     {
         var objectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
         yield return(_entityService.Get(relation.ParentId, objectType));
     }
 }
 /// <summary>
 /// Gets the Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
 /// </summary>
 /// <param name="relations">List of relations to retrieve child objects from</param>
 /// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
 /// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
 public IEnumerable <IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable <IRelation> relations, bool loadBaseType = false)
 {
     foreach (var relation in relations)
     {
         var objectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
         yield return(_entityService.Get(relation.ChildId, objectType, loadBaseType));
     }
 }
        /// <summary>
        /// Gets the Parent and Child objects from a Relation as a <see cref="Tuple"/>"/> with <see cref="IUmbracoEntity"/>.
        /// </summary>
        /// <param name="relation">Relation to retrieve parent and child object from</param>
        /// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
        /// <returns>Returns a Tuple with Parent (item1) and Child (item2)</returns>
        public Tuple <IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation, bool loadBaseType = false)
        {
            var childObjectType  = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
            var parentObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ParentObjectType);

            var child  = _entityService.Get(relation.ChildId, childObjectType, loadBaseType);
            var parent = _entityService.Get(relation.ParentId, parentObjectType, loadBaseType);

            return(new Tuple <IUmbracoEntity, IUmbracoEntity>(parent, child));
        }
 /// <summary>
 /// Gets the UmbracoObjectType from the integer id of an IUmbracoEntity.
 /// </summary>
 /// <param name="key">Unique Id of the entity</param>
 /// <returns><see cref="UmbracoObjectTypes"/></returns>
 public virtual UmbracoObjectTypes GetObjectType(Guid key)
 {
     using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
     {
         var sql = new Sql().Select("nodeObjectType").From <NodeDto>().Where <NodeDto>(x => x.UniqueId == key);
         var nodeObjectTypeId = uow.Database.ExecuteScalar <Guid>(sql);
         var objectTypeId     = nodeObjectTypeId;
         return(UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId));
     }
 }
예제 #8
0
 /// <summary>
 /// Gets the UmbracoObjectType from the integer id of an IUmbracoEntity.
 /// </summary>
 /// <param name="id">Id of the entity</param>
 /// <returns><see cref="UmbracoObjectTypes"/></returns>
 public virtual UmbracoObjectTypes GetObjectType(int id)
 {
     using (var uow = _uowProvider.GetUnitOfWork())
     {
         var sql = new Sql().Select("nodeObjectType").From <NodeDto>().Where <NodeDto>(x => x.NodeId == id);
         var nodeObjectTypeId = uow.Database.ExecuteScalar <string>(sql);
         var objectTypeId     = new Guid(nodeObjectTypeId);
         return(UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId));
     }
 }
        /// <summary>
        /// On Load event
        /// </summary>
        /// <param name="sender">this aspx page</param>
        /// <param name="e">EventArgs (expect empty)</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            int id;

            if (int.TryParse(Request.QueryString["id"], out id))
            {
                var relationService = Services.RelationService;

                this._relationType = relationService.GetRelationTypeById(id);
                if (this._relationType != null)
                {
                    this._parentObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(this._relationType.ParentObjectType);
                    this._childObjectType  = UmbracoObjectTypesExtensions.GetUmbracoObjectType(this._relationType.ChildObjectType);

                    // -----------

                    if (!this.IsPostBack)
                    {
                        this.EnsureChildControls();

                        this.idLiteral.Text    = this._relationType.Id.ToString();
                        this.nameTextBox.Text  = this._relationType.Name;
                        this.aliasTextBox.Text = this._relationType.Alias;

                        if (this._relationType.IsBidirectional)
                        {
                            this.dualRadioButtonList.Items.FindByValue("1").Selected = true;
                        }
                        else
                        {
                            this.dualRadioButtonList.Items.FindByValue("0").Selected = true;
                        }

                        this.parentLiteral.Text = this._parentObjectType.GetFriendlyName();
                        // UmbracoHelper.GetFriendlyName(this.parentObjectType);
                        this.childLiteral.Text = this._childObjectType.GetFriendlyName();
                        // UmbracoHelper.GetFriendlyName(this.childObjectType);

                        this.relationsCountLiteral.Text = this.Relations.Count.ToString();

                        this.relationsRepeater.DataSource = this.Relations;
                        this.relationsRepeater.DataBind();
                    }
                }
                else
                {
                    throw new Exception("Unable to get RelationType where ID = " + id);
                }
            }
            else
            {
                throw new Exception("Invalid RelationType ID");
            }
        }
예제 #10
0
        /// <summary>
        /// Gets the UmbracoObjectType from an IUmbracoEntity.
        /// </summary>
        /// <param name="entity"><see cref="IUmbracoEntity"/></param>
        /// <returns><see cref="UmbracoObjectTypes"/></returns>
        public virtual UmbracoObjectTypes GetObjectType(IUmbracoEntity entity)
        {
            var entityImpl = entity as UmbracoEntity;

            if (entityImpl == null)
            {
                return(GetObjectType(entity.Id));
            }

            return(UmbracoObjectTypesExtensions.GetUmbracoObjectType(entityImpl.NodeObjectTypeId));
        }
예제 #11
0
        /// <summary>
        /// Gets the Parent and Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
        /// </summary>
        /// <param name="relations">List of relations to retrieve parent and child objects from</param>
        /// <returns>An enumerable list of <see cref="Tuple"/> with <see cref="IUmbracoEntity"/></returns>
        public IEnumerable <Tuple <IUmbracoEntity, IUmbracoEntity> > GetEntitiesFromRelations(
            IEnumerable <IRelation> relations)
        {
            foreach (var relation in relations)
            {
                var childObjectType  = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
                var parentObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ParentObjectType);

                var child  = _entityService.Get(relation.ChildId, childObjectType);
                var parent = _entityService.Get(relation.ParentId, parentObjectType);

                yield return(new Tuple <IUmbracoEntity, IUmbracoEntity>(parent, child));
            }
        }
예제 #12
0
        /// <summary>
        /// Gets a collection of <see cref="IUmbracoEntity"/>
        /// </summary>
        /// <param name="objectTypeId">Guid id of the UmbracoObjectType</param>
        /// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
        public virtual IEnumerable <IUmbracoEntity> GetAll(Guid objectTypeId)
        {
            var umbracoObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
            var entityType        = GetEntityType(umbracoObjectType);
            var typeFullName      = entityType.FullName;

            Mandate.That <NotSupportedException>(_supportedObjectTypes.ContainsKey(typeFullName), () =>
            {
                throw new NotSupportedException
                    ("The passed in type is not supported");
            });

            using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork()))
            {
                return(repository.GetAll(objectTypeId));
            }
        }
예제 #13
0
        private IUmbracoEntity GetEntity(Guid childObjectType, int childId)
        {
            switch (UmbracoObjectTypesExtensions.GetUmbracoObjectType(childObjectType))
            {
            case UmbracoObjectTypes.Document:
                return(contentService.GetById(childId));

            case UmbracoObjectTypes.Media:
                return(mediaService.GetById(childId));

            case UmbracoObjectTypes.DocumentType:
                return(contentTypeService.GetContentType(childId));

            case UmbracoObjectTypes.MediaType:
                return(contentTypeService.GetMediaType(childId));
            }
            throw new Exception("Unknown child type");
        }
예제 #14
0
        private void TreeControllerBaseOnTreeNodesRendering(TreeControllerBase sender, TreeNodesRenderingEventArgs eventArgs)
        {
            if (eventArgs.QueryStrings.HasKey("relationEditor"))
            {
                var parentType    = (UmbracoObjectTypes)Enum.Parse(typeof(UmbracoObjectTypes), eventArgs.QueryStrings.Get("parentType"));
                var parentAlias   = eventArgs.QueryStrings.Get("parentTypeAlias");
                var relationAlias = eventArgs.QueryStrings.Get("relationAlias");

                var config = Configuration.Get(parentType, parentAlias);
                if (!config.Enabled)
                {
                    return;
                }

                var relConfig = config.Get(relationAlias);
                if (!relConfig.Enabled)
                {
                    return;
                }

                var childTypes = relConfig.EnabledChildTypes.Select(t => t.Alias).ToArray();

                if (!childTypes.Any())
                {
                    return;
                }

                var relation        = UmbracoContext.Current.Application.Services.RelationService.GetRelationTypeByAlias(relationAlias);
                var childObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.ChildObjectType);

                foreach (var node in eventArgs.Nodes)
                {
                    var id    = Convert.ToInt32(node.Id);
                    var alias = EntityHelper.FindAlias(childObjectType, id);
                    if (!alias.IsNullOrWhiteSpace() && !childTypes.Contains(alias, IgnoreCase))
                    {
                        node.SetNotPublishedStyle();
                        node.AdditionalData.Add("relationDisallowed", "true");
                    }
                }
            }
        }
        /// <summary>
        /// The method called to render the contents of the tree structure
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryStrings">
        /// All of the query string parameters passed from jsTree
        /// </param>
        /// <remarks>
        /// We are allowing an arbitrary number of query strings to be pased in so that developers are able to persist custom data from the front-end
        /// to the back end to be used in the query for model data.
        /// </remarks>
        protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
        {
            var nodes = new TreeNodeCollection();

            var found = id == Constants.System.Root.ToInvariantString()
                ? Services.FileService.GetTemplates(-1)
                : Services.FileService.GetTemplates(int.Parse(id));

            nodes.AddRange(found.Select(template => CreateTreeNode(
                                            template.Id.ToString(CultureInfo.InvariantCulture),
                                            //TODO: Fix parent ID stuff for templates
                                            "-1",
                                            queryStrings,
                                            template.Name,
                                            template.IsMasterTemplate ? "icon-newspaper" : "icon-newspaper-alt",
                                            template.IsMasterTemplate,
                                            GetEditorPath(template, queryStrings),
                                            Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(Constants.ObjectTypes.TemplateTypeGuid), template.Key)
                                            )));

            return(nodes);
        }
예제 #16
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="contextId">the id of the content, media or member item</param>
        /// <param name="propertyAlias">the property alias of the picker using relation mapping</param>
        /// <param name="relationTypeAlias">the alias of the relation type to use</param>
        /// <param name="relationsOnly"></param>
        /// <param name="pickedIds">the ids of all picked items that are to be related to the contextId</param>
        internal static void UpdateRelationMapping(int contextId, string propertyAlias, string relationTypeAlias, bool relationsOnly, int[] pickedIds)
        {
            IRelationType relationType = ApplicationContext.Current.Services.RelationService.GetRelationTypeByAlias(relationTypeAlias);

            if (relationType != null)
            {
                // get all relations of this type
                List <IRelation> relations = ApplicationContext.Current.Services.RelationService.GetAllRelationsByRelationType(relationType.Id).ToList();

                // construct object used to identify a relation (this is serialized into the relation comment field)
                RelationMappingComment relationMappingComment = new RelationMappingComment(contextId, propertyAlias);

                // filter down potential relations, by relation type direction
                if (relationType.IsBidirectional && relationsOnly)
                {
                    relations = relations.Where(x => x.ChildId == contextId || x.ParentId == contextId).ToList();
                    relations = relations.Where(x => new RelationMappingComment(x.Comment).DataTypeDefinitionId == relationMappingComment.DataTypeDefinitionId).ToList();
                }
                else
                {
                    relations = relations.Where(x => x.ChildId == contextId).ToList();
                    relations = relations.Where(x => new RelationMappingComment(x.Comment).PropertyTypeId == relationMappingComment.PropertyTypeId).ToList();

                    if (relationMappingComment.IsInArchetype())
                    {
                        relations = relations.Where(x => new RelationMappingComment(x.Comment).MatchesArchetypeProperty(relationMappingComment.PropertyAlias)).ToList();
                    }
                }

                // check current context is of the correct object type (as according to the relation type)
                if (ApplicationContext.Current.Services.EntityService.GetObjectType(contextId) == UmbracoObjectTypesExtensions.GetUmbracoObjectType(relationType.ChildObjectType))
                {
                    // for each picked item
                    foreach (int pickedId in pickedIds)
                    {
                        // check picked item context if of the correct object type (as according to the relation type)
                        if (ApplicationContext.Current.Services.EntityService.GetObjectType(pickedId) == UmbracoObjectTypesExtensions.GetUmbracoObjectType(relationType.ParentObjectType))
                        {
                            // if relation doesn't already exist (new picked item)
                            if (!relations.Exists(x => x.ParentId == pickedId))
                            {
                                // create relation
                                Relation relation = new Relation(pickedId, contextId, relationType);
                                relation.Comment = relationMappingComment.GetComment();
                                ApplicationContext.Current.Services.RelationService.Save(relation);
                            }

                            // housekeeping - remove 'the' relation from the list being processed (there should be only one)
                            relations.RemoveAll(x => x.ChildId == contextId && x.ParentId == pickedId && x.RelationTypeId == relationType.Id);
                        }
                    }
                }

                // delete relations for any items left on the list being processed
                if (relations.Any())
                {
                    foreach (IRelation relation in relations)
                    {
                        ApplicationContext.Current.Services.RelationService.Delete(relation);
                    }
                }
            }
        }
예제 #17
0
        public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
        {
            config.CreateMap <UmbracoEntity, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
            .ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.Alias, expression => expression.Ignore())
            .AfterMap((entity, basic) =>
            {
                if (entity.NodeObjectTypeId == Constants.ObjectTypes.MemberGuid && basic.Icon.IsNullOrWhiteSpace())
                {
                    basic.Icon = "icon-user";
                }
            });

            config.CreateMap <PropertyType, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.Ignore())
            .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-box"))
            .ForMember(basic => basic.Path, expression => expression.UseValue(""))
            .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore());

            config.CreateMap <PropertyGroup, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.Ignore())
            .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-tab"))
            .ForMember(basic => basic.Path, expression => expression.UseValue(""))
            .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1))
            //in v6 the 'alias' is it's lower cased name so we'll stick to that.
            .ForMember(basic => basic.Alias, expression => expression.MapFrom(group => group.Name.ToLowerInvariant()))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore());

            config.CreateMap <IUser, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.Ignore())
            .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-user"))
            .ForMember(basic => basic.Path, expression => expression.UseValue(""))
            .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1))
            .ForMember(basic => basic.Alias, expression => expression.MapFrom(user => user.Username))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore());

            config.CreateMap <ITemplate, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(Constants.UdiEntityType.Template, x.Key)))
            .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-layout"))
            .ForMember(basic => basic.Path, expression => expression.MapFrom(template => template.Path))
            .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore());

            config.CreateMap <EntityBasic, ContentTypeSort>()
            .ForMember(x => x.Id, expression => expression.MapFrom(entity => new Lazy <int>(() => Convert.ToInt32(entity.Id))))
            .ForMember(x => x.SortOrder, expression => expression.Ignore());

            config.CreateMap <IContentTypeComposition, EntityBasic>()
            .ForMember(x => x.Udi, expression => expression.ResolveUsing(new ContentTypeUdiResolver()))
            .ForMember(basic => basic.Path, expression => expression.MapFrom(x => x.Path))
            .ForMember(basic => basic.ParentId, expression => expression.MapFrom(x => x.ParentId))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore());

            config.CreateMap <UmbracoEntity, SearchResultItem>()
            .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
            .ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.Alias, expression => expression.Ignore())
            .ForMember(x => x.Score, expression => expression.Ignore())
            .AfterMap((entity, basic) =>
            {
                if (basic.Icon.IsNullOrWhiteSpace())
                {
                    if (entity.NodeObjectTypeId == Constants.ObjectTypes.MemberGuid)
                    {
                        basic.Icon = "icon-user";
                    }
                    else if (entity.NodeObjectTypeId == Constants.ObjectTypes.DataTypeGuid)
                    {
                        basic.Icon = "icon-autofill";
                    }
                    else if (entity.NodeObjectTypeId == Constants.ObjectTypes.DocumentTypeGuid)
                    {
                        basic.Icon = "icon-item-arrangement";
                    }
                    else if (entity.NodeObjectTypeId == Constants.ObjectTypes.MediaTypeGuid)
                    {
                        basic.Icon = "icon-thumbnails";
                    }
                    else if (entity.NodeObjectTypeId == Constants.ObjectTypes.TemplateTypeGuid)
                    {
                        basic.Icon = "icon-newspaper-alt";
                    }
                }
            });

            config.CreateMap <SearchResult, SearchResultItem>()
            //default to document icon
            .ForMember(x => x.Score, expression => expression.MapFrom(result => result.Score))
            .ForMember(x => x.Udi, expression => expression.Ignore())
            .ForMember(x => x.Icon, expression => expression.Ignore())
            .ForMember(x => x.Id, expression => expression.MapFrom(result => result.Id))
            .ForMember(x => x.Name, expression => expression.Ignore())
            .ForMember(x => x.Key, expression => expression.Ignore())
            .ForMember(x => x.ParentId, expression => expression.Ignore())
            .ForMember(x => x.Alias, expression => expression.Ignore())
            .ForMember(x => x.Path, expression => expression.Ignore())
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.AdditionalData, expression => expression.Ignore())
            .AfterMap((result, basic) =>
            {
                //get the icon if there is one
                basic.Icon = result.Fields.ContainsKey(UmbracoContentIndexer.IconFieldName)
                              ? result.Fields[UmbracoContentIndexer.IconFieldName]
                              : "icon-document";

                basic.Name = result.Fields.ContainsKey("nodeName") ? result.Fields["nodeName"] : "[no name]";
                if (result.Fields.ContainsKey(UmbracoContentIndexer.NodeKeyFieldName))
                {
                    Guid key;
                    if (Guid.TryParse(result.Fields[UmbracoContentIndexer.NodeKeyFieldName], out key))
                    {
                        basic.Key = key;

                        //need to set the UDI
                        if (result.Fields.ContainsKey(LuceneIndexer.IndexTypeFieldName))
                        {
                            switch (result.Fields[LuceneIndexer.IndexTypeFieldName])
                            {
                            case IndexTypes.Member:
                                basic.Udi = new GuidUdi(Constants.UdiEntityType.Member, basic.Key);
                                break;

                            case IndexTypes.Content:
                                basic.Udi = new GuidUdi(Constants.UdiEntityType.Document, basic.Key);
                                break;

                            case IndexTypes.Media:
                                basic.Udi = new GuidUdi(Constants.UdiEntityType.Media, basic.Key);
                                break;
                            }
                        }
                    }
                }

                if (result.Fields.ContainsKey("parentID"))
                {
                    int parentId;
                    if (int.TryParse(result.Fields["parentID"], out parentId))
                    {
                        basic.ParentId = parentId;
                    }
                    else
                    {
                        basic.ParentId = -1;
                    }
                }
                basic.Path = result.Fields.ContainsKey(UmbracoContentIndexer.IndexPathFieldName) ? result.Fields[UmbracoContentIndexer.IndexPathFieldName] : "";

                if (result.Fields.ContainsKey(UmbracoContentIndexer.NodeTypeAliasFieldName))
                {
                    basic.AdditionalData.Add("contentType", result.Fields[UmbracoContentIndexer.NodeTypeAliasFieldName]);
                }
            });

            config.CreateMap <ISearchResults, IEnumerable <SearchResultItem> >()
            .ConvertUsing(results => results.Select(Mapper.Map <SearchResultItem>).ToList());

            config.CreateMap <IEnumerable <SearchResult>, IEnumerable <SearchResultItem> >()
            .ConvertUsing(results => results.Select(Mapper.Map <SearchResultItem>).ToList());
        }
예제 #18
0
        /// <summary>
        /// Gets the Child object from a Relation as an <see cref="IUmbracoEntity"/>
        /// </summary>
        /// <param name="relation">Relation to retrieve child object from</param>
        /// <returns>An <see cref="IUmbracoEntity"/></returns>
        public IUmbracoEntity GetChildEntityFromRelation(IRelation relation)
        {
            var objectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ChildObjectType);

            return(_entityService.Get(relation.ChildId, objectType));
        }
        /// <summary>
        /// Gets the Parent object from a Relation as an <see cref="IUmbracoEntity"/>
        /// </summary>
        /// <param name="relation">Relation to retrieve parent object from</param>
        /// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
        /// <returns>An <see cref="IUmbracoEntity"/></returns>
        public IUmbracoEntity GetParentEntityFromRelation(IRelation relation, bool loadBaseType = false)
        {
            var objectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(relation.RelationType.ParentObjectType);

            return(_entityService.Get(relation.ParentId, objectType, loadBaseType));
        }
        public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
        {
            config.CreateMap <UserGroupSave, IUserGroup>()
            .ConstructUsing((UserGroupSave save) => new UserGroup()
            {
                CreateDate = DateTime.Now
            })
            .IgnoreDeletableEntityCommonProperties()
            .ForMember(dest => dest.Id, map => map.Condition(source => GetIntId(source.Id) > 0))
            .ForMember(dest => dest.Id, map => map.MapFrom(source => GetIntId(source.Id)))
            .ForMember(dest => dest.Permissions, map => map.MapFrom(source => source.DefaultPermissions))
            .AfterMap((save, userGroup) =>
            {
                userGroup.ClearAllowedSections();
                foreach (var section in save.Sections)
                {
                    userGroup.AddAllowedSection(section);
                }
            });

            //Used for merging existing UserSave to an existing IUser instance - this will not create an IUser instance!
            config.CreateMap <UserSave, IUser>()
            .IgnoreDeletableEntityCommonProperties()
            .ForMember(dest => dest.Id, map => map.Condition(source => GetIntId(source.Id) > 0))
            .ForMember(detail => detail.SessionTimeout, opt => opt.Ignore())
            .ForMember(detail => detail.EmailConfirmedDate, opt => opt.Ignore())
            .ForMember(detail => detail.UserType, opt => opt.Ignore())
            .ForMember(detail => detail.StartContentId, opt => opt.Ignore())
            .ForMember(detail => detail.StartMediaId, opt => opt.Ignore())
            .ForMember(detail => detail.InvitedDate, opt => opt.Ignore())
            .ForMember(detail => detail.SecurityStamp, opt => opt.Ignore())
            .ForMember(detail => detail.Avatar, opt => opt.Ignore())
            .ForMember(detail => detail.ProviderUserKey, opt => opt.Ignore())
            .ForMember(detail => detail.RawPasswordValue, opt => opt.Ignore())
            .ForMember(detail => detail.RawPasswordAnswerValue, opt => opt.Ignore())
            .ForMember(detail => detail.PasswordQuestion, opt => opt.Ignore())
            .ForMember(detail => detail.Comments, opt => opt.Ignore())
            .ForMember(detail => detail.IsApproved, opt => opt.Ignore())
            .ForMember(detail => detail.IsLockedOut, opt => opt.Ignore())
            .ForMember(detail => detail.LastLoginDate, opt => opt.Ignore())
            .ForMember(detail => detail.LastPasswordChangeDate, opt => opt.Ignore())
            .ForMember(detail => detail.LastLockoutDate, opt => opt.Ignore())
            .ForMember(detail => detail.FailedPasswordAttempts, opt => opt.Ignore())
            .ForMember(user => user.Language, expression => expression.MapFrom(save => save.Culture))
            .AfterMap((save, user) =>
            {
                user.ClearGroups();
                var foundGroups = applicationContext.Services.UserService.GetUserGroupsByAlias(save.UserGroups.ToArray());
                foreach (var group in foundGroups)
                {
                    user.AddGroup(group.ToReadOnlyGroup());
                }
            });

            config.CreateMap <UserInvite, IUser>()
            .IgnoreDeletableEntityCommonProperties()
            .ForMember(detail => detail.Id, opt => opt.Ignore())
            .ForMember(detail => detail.StartContentIds, opt => opt.Ignore())
            .ForMember(detail => detail.StartMediaIds, opt => opt.Ignore())
            .ForMember(detail => detail.UserType, opt => opt.Ignore())
            .ForMember(detail => detail.StartContentId, opt => opt.Ignore())
            .ForMember(detail => detail.StartMediaId, opt => opt.Ignore())
            .ForMember(detail => detail.Language, opt => opt.Ignore())
            .ForMember(detail => detail.Username, opt => opt.Ignore())
            .ForMember(detail => detail.PasswordQuestion, opt => opt.Ignore())
            .ForMember(detail => detail.SessionTimeout, opt => opt.Ignore())
            .ForMember(detail => detail.EmailConfirmedDate, opt => opt.Ignore())
            .ForMember(detail => detail.InvitedDate, opt => opt.Ignore())
            .ForMember(detail => detail.SecurityStamp, opt => opt.Ignore())
            .ForMember(detail => detail.Avatar, opt => opt.Ignore())
            .ForMember(detail => detail.ProviderUserKey, opt => opt.Ignore())
            .ForMember(detail => detail.RawPasswordValue, opt => opt.Ignore())
            .ForMember(detail => detail.RawPasswordAnswerValue, opt => opt.Ignore())
            .ForMember(detail => detail.Comments, opt => opt.Ignore())
            .ForMember(detail => detail.IsApproved, opt => opt.Ignore())
            .ForMember(detail => detail.IsLockedOut, opt => opt.Ignore())
            .ForMember(detail => detail.LastLoginDate, opt => opt.Ignore())
            .ForMember(detail => detail.LastPasswordChangeDate, opt => opt.Ignore())
            .ForMember(detail => detail.LastLockoutDate, opt => opt.Ignore())
            .ForMember(detail => detail.FailedPasswordAttempts, opt => opt.Ignore())
            //all invited users will not be approved, completing the invite will approve the user
            .ForMember(user => user.IsApproved, expression => expression.UseValue(false))
            .AfterMap((invite, user) =>
            {
                user.ClearGroups();
                var foundGroups = applicationContext.Services.UserService.GetUserGroupsByAlias(invite.UserGroups.ToArray());
                foreach (var group in foundGroups)
                {
                    user.AddGroup(group.ToReadOnlyGroup());
                }
            });

            config.CreateMap <IReadOnlyUserGroup, UserGroupBasic>()
            .ForMember(detail => detail.ContentStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.UserCount, opt => opt.Ignore())
            .ForMember(detail => detail.MediaStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.Key, opt => opt.Ignore())
            .ForMember(detail => detail.Sections, opt => opt.Ignore())
            .ForMember(detail => detail.Notifications, opt => opt.Ignore())
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id))
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore())
            .AfterMap((group, display) =>
            {
                MapUserGroupBasic(applicationContext.Services, group, display);
            });

            config.CreateMap <IUserGroup, UserGroupBasic>()
            .ForMember(detail => detail.ContentStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.MediaStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.Sections, opt => opt.Ignore())
            .ForMember(detail => detail.Notifications, opt => opt.Ignore())
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id))
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore())
            .AfterMap((group, display) =>
            {
                MapUserGroupBasic(applicationContext.Services, group, display);
            });

            //create a map to assign a user group's default permissions to the AssignedUserGroupPermissions instance
            config.CreateMap <IUserGroup, AssignedUserGroupPermissions>()
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore())
            .ForMember(detail => detail.Id, opt => opt.MapFrom(group => group.Id))
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id))
            .ForMember(detail => detail.DefaultPermissions, expression => expression.ResolveUsing(new UserGroupDefaultPermissionsResolver(applicationContext.Services.TextService)))
            //these will be manually mapped and by default they are null
            .ForMember(detail => detail.AssignedPermissions, opt => opt.Ignore())
            .AfterMap((group, display) =>
            {
                if (display.Icon.IsNullOrWhiteSpace())
                {
                    display.Icon = "icon-users";
                }
            });

            config.CreateMap <UmbracoEntity, AssignedContentPermissions>()
            .ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
            .ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
            .ForMember(dto => dto.Trashed, expression => expression.Ignore())
            .ForMember(x => x.Alias, expression => expression.Ignore())
            .ForMember(x => x.AssignedPermissions, expression => expression.Ignore())
            .AfterMap((entity, basic) =>
            {
                if (entity.NodeObjectTypeId == Constants.ObjectTypes.MemberGuid && basic.Icon.IsNullOrWhiteSpace())
                {
                    basic.Icon = "icon-user";
                }
            });

            config.CreateMap <IUserGroup, UserGroupDisplay>()
            .ForMember(detail => detail.ContentStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.MediaStartNode, opt => opt.Ignore())
            .ForMember(detail => detail.Sections, opt => opt.Ignore())
            .ForMember(detail => detail.Notifications, opt => opt.Ignore())
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id))
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore())
            .ForMember(detail => detail.Users, opt => opt.Ignore())
            .ForMember(detail => detail.DefaultPermissions, expression => expression.ResolveUsing(new UserGroupDefaultPermissionsResolver(applicationContext.Services.TextService)))
            .ForMember(detail => detail.AssignedPermissions, opt => opt.Ignore())
            .AfterMap((group, display) =>
            {
                MapUserGroupBasic(applicationContext.Services, group, display);

                //Important! Currently we are never mapping to multiple UserGroupDisplay objects but if we start doing that
                // this will cause an N+1 and we'll need to change how this works.
                var users     = applicationContext.Services.UserService.GetAllInGroup(group.Id);
                display.Users = Mapper.Map <IEnumerable <UserBasic> >(users);

                //Deal with assigned permissions:

                var allContentPermissions = applicationContext.Services.UserService.GetPermissions(@group, true)
                                            .ToDictionary(x => x.EntityId, x => x);

                var contentEntities = allContentPermissions.Keys.Count == 0
                        ? new IUmbracoEntity[0]
                        : applicationContext.Services.EntityService.GetAll(UmbracoObjectTypes.Document, allContentPermissions.Keys.ToArray());

                var allAssignedPermissions = new List <AssignedContentPermissions>();
                foreach (var entity in contentEntities)
                {
                    var contentPermissions = allContentPermissions[entity.Id];

                    var assignedContentPermissions = Mapper.Map <AssignedContentPermissions>(entity);
                    assignedContentPermissions.AssignedPermissions = AssignedUserGroupPermissions.ClonePermissions(display.DefaultPermissions);

                    //since there is custom permissions assigned to this node for this group, we need to clear all of the default permissions
                    //and we'll re-check it if it's one of the explicitly assigned ones
                    foreach (var permission in assignedContentPermissions.AssignedPermissions.SelectMany(x => x.Value))
                    {
                        permission.Checked = false;
                        permission.Checked = contentPermissions.AssignedPermissions.Contains(permission.PermissionCode, StringComparer.InvariantCulture);
                    }

                    allAssignedPermissions.Add(assignedContentPermissions);
                }

                display.AssignedPermissions = allAssignedPermissions;
            });

            //Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that
            // this will cause an N+1 and we'll need to change how this works.
            config.CreateMap <IUser, UserDisplay>()
            .ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache)))
            .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
            .ForMember(detail => detail.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate))
            .ForMember(detail => detail.UserGroups, opt => opt.MapFrom(user => user.Groups))
            .ForMember(
                detail => detail.CalculatedStartContentIds,
                opt => opt.MapFrom(user => GetStartNodeValues(
                                       user.CalculateContentStartNodeIds(applicationContext.Services.EntityService),
                                       applicationContext.Services.TextService,
                                       applicationContext.Services.EntityService,
                                       UmbracoObjectTypes.Document,
                                       "content/contentRoot")))
            .ForMember(
                detail => detail.CalculatedStartMediaIds,
                opt => opt.MapFrom(user => GetStartNodeValues(
                                       user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService),
                                       applicationContext.Services.TextService,
                                       applicationContext.Services.EntityService,
                                       UmbracoObjectTypes.Media,
                                       "media/mediaRoot")))
            .ForMember(
                detail => detail.StartContentIds,
                opt => opt.MapFrom(user => GetStartNodeValues(
                                       user.StartContentIds.ToArray(),
                                       applicationContext.Services.TextService,
                                       applicationContext.Services.EntityService,
                                       UmbracoObjectTypes.Document,
                                       "content/contentRoot")))
            .ForMember(
                detail => detail.StartMediaIds,
                opt => opt.MapFrom(user => GetStartNodeValues(
                                       user.StartMediaIds.ToArray(),
                                       applicationContext.Services.TextService,
                                       applicationContext.Services.EntityService,
                                       UmbracoObjectTypes.Media,
                                       "media/mediaRoot")))
            .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
            .ForMember(
                detail => detail.AvailableCultures,
                opt => opt.MapFrom(user => applicationContext.Services.TextService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName)))
            .ForMember(
                detail => detail.EmailHash,
                opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().GenerateHash()))
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(user => "-1," + user.Id))
            .ForMember(detail => detail.Notifications, opt => opt.Ignore())
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Icon, opt => opt.Ignore())
            .ForMember(detail => detail.IsCurrentUser, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.ResetPasswordValue, opt => opt.Ignore())
            .ForMember(detail => detail.Alias, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore());

            config.CreateMap <IUser, UserBasic>()
            //Loading in the user avatar's requires an external request if they don't have a local file avatar, this means that initial load of paging may incur a cost
            //Alternatively, if this is annoying the back office UI would need to be updated to request the avatars for the list of users separately so it doesn't look
            //like the load time is waiting.
            .ForMember(detail =>
                       detail.Avatars,
                       opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache)))
            .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
            .ForMember(detail => detail.UserGroups, opt => opt.MapFrom(user => user.Groups))
            .ForMember(detail => detail.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate))
            .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
            .ForMember(
                detail => detail.EmailHash,
                opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5()))
            .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1))
            .ForMember(detail => detail.Path, opt => opt.MapFrom(user => "-1," + user.Id))
            .ForMember(detail => detail.Notifications, opt => opt.Ignore())
            .ForMember(detail => detail.IsCurrentUser, opt => opt.Ignore())
            .ForMember(detail => detail.Udi, opt => opt.Ignore())
            .ForMember(detail => detail.Icon, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.Alias, opt => opt.Ignore())
            .ForMember(detail => detail.Trashed, opt => opt.Ignore())
            .ForMember(detail => detail.AdditionalData, opt => opt.Ignore());

            config.CreateMap <IUser, UserDetail>()
            .ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache)))
            .ForMember(detail => detail.UserId, opt => opt.MapFrom(user => GetIntId(user.Id)))
            .ForMember(detail => detail.StartContentIds, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
            .ForMember(detail => detail.StartMediaIds, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
            .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
            .ForMember(
                detail => detail.EmailHash,
                opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().GenerateHash()))
            .ForMember(detail => detail.SecondsUntilTimeout, opt => opt.Ignore())
            .ForMember(detail => detail.UserGroups, opt => opt.Ignore())
            .AfterMap((user, detail) =>
            {
                //we need to map the legacy UserType
                //the best we can do here is to return the user's first user group as a IUserType object
                //but we should attempt to return any group that is the built in ones first
                var groups        = user.Groups.ToArray();
                detail.UserGroups = user.Groups.Select(x => x.Alias).ToArray();

                if (groups.Length == 0)
                {
                    //In backwards compatibility land, a user type cannot be null! so we need to return a fake one.
                    detail.UserType = "temp";
                }
                else
                {
                    var builtIns     = new[] { Constants.Security.AdminGroupAlias, "writer", "editor", Constants.Security.TranslatorGroupAlias };
                    var foundBuiltIn = groups.FirstOrDefault(x => builtIns.Contains(x.Alias));
                    if (foundBuiltIn != null)
                    {
                        detail.UserType = foundBuiltIn.Alias;
                    }
                    else
                    {
                        //otherwise return the first
                        detail.UserType = groups[0].Alias;
                    }
                }
            });

            config.CreateMap <IProfile, UserProfile>()
            .ForMember(detail => detail.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id)));

            config.CreateMap <IUser, UserData>()
            .ConstructUsing((IUser user) => new UserData())
            .ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
            .ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections.ToArray()))
            .ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
            .ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Groups.Select(x => x.Alias).ToArray()))
            .ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
            .ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
            .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
            .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
            .ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
        }