Add a Dynamic Content selector to a User Profile

Add a Dynamic Content selector to a User Profile

Introduction

For a project I was working on I needed to create a relation between Projects (which is an entity from my Sitefinity Module Builder) and a Sitefinity User. There are a couple of ways to do this and I choose one that fits the actual need of my client.

What do we need?

  1. We first need a Dynamic Module, created with the Module Builder that holds project information. In my case this was a really simple entity. Title, Date, Documents.
  2. Second we to create a selector field, which allows us to pick one or more projects. The results of this selector are returned as a Guid array.
  3. Last thing we need is a new custom field in our user profile which will hold the Projects that we select through our selector.

The problem

Sounds fairly simple, but the thing is that through the Sitefinity interface it is currently not possible to add custom fields of type Guid[] (a Guid array). So even if we can enter a custom field like our project selector, created by Sitefinity Thunder, it wouldn't work, since it expects that the results are stored inside this field of type Guid[].

The solution

At this time we can't do other then do this through code, by using the Sitefinity API's. We can create a new custom field of type Guid[] and then edit all the views to add the project selector. These views are for example when you create a user, edit a user etc.

The following method helps us create a new field and the related selector. It is a generic methods, so you can use it for other field elements also.

/// <summary>
        /// Register a custom field for a specific User Profile
        /// </summary>
        /// <typeparam name="TE"></typeparam>
        /// <param name="userProfileType"></param>
        /// <param name="fieldName"></param>
        /// <example></example>
        public static void RegisterFieldForUserProfile<TE>(string userProfileType, string fieldName)
           where TE : FieldControlDefinitionElement {
 
            // Check if the field is not already present for this content type
            UserProfileManager.GetManager();
            var itemClrType = TypeResolutionService.ResolveType(userProfileType);
 
            // Specify the persistent filed CLR type (e.g. String, Guid[], ContentLink).
            // Please ensure your custom field has been properly implemented to work with that CLR type
            var persistentFieldType = typeof(Guid[]);
            var itemType = itemClrType.FullName;
 
            // Check to see if the field exists
            var fieldExists = GetMetaFieldsForType(itemType).SingleOrDefault(f => f.FieldName == fieldName) != null;
            if (fieldExists) return;
 
            // Add the metafield that will hold the data to the profile
            App.WorkWith()
                .DynamicData()
                .Type(itemClrType)
                .Field()
                .TryCreateNew(fieldName, persistentFieldType)
                .SaveChanges(true);
 
            // Get correct module configuration depending on item type
            var manager = ConfigManager.GetManager();
 
            // Suppress the security
            var suppressSecurityChecks = manager.Provider.SuppressSecurityChecks;
            manager.Provider.SuppressSecurityChecks = true;
 
            // Get Backend views(e.g. Edit, Create) configuration
            var section = Config.Get<ContentViewConfig>();
            var profileTypeName = userProfileType.Replace("Telerik.Sitefinity.Security.Model.", "");
            var definitionName = "ProfileType_" + profileTypeName;
            var backendSection = section.ContentViewControls[definitionName];
            var views = backendSection.ViewsConfig.Values.Where(v => v.ViewType == typeof(DetailFormView));
 
            foreach (DetailFormViewElement view in views) {
 
                // If there are no custom fields added before, the new field will be placed int he CustomFieldsSection
                var sectionToInsert = CustomFieldsContext.GetSection(view, CustomFieldsContext.customFieldsSectionName, itemType);
                var fieldConfigElementType = TypeResolutionService.ResolveType(typeof(TE).FullName);
 
                // Create a new instance of our field configuration in the current view configuration
                var newElement = Activator.CreateInstance(fieldConfigElementType, new object[] { sectionToInsert.Fields }) as TE;
 
                // Populate custom field values
                if (newElement == null) continue;
                newElement.DataFieldName = fieldName;
                newElement.FieldName = fieldName;
                newElement.Title = fieldName;
                newElement.DisplayMode = FieldDisplayMode.Write;
 
                sectionToInsert.Fields.Add(newElement);
            }
 
            // Save and restart the application
            manager.SaveSection(section);
            manager.Provider.SuppressSecurityChecks = suppressSecurityChecks;
            SystemManager.RestartApplication(true);
        }

We also use this helper method to check if the field exists

/// <summary>
        /// Returns an IList of Meta Fields for the specified type
        /// </summary>
        public static IList<MetaField> GetMetaFieldsForType(string type) {
 
            var existingType = TypeResolutionService.ResolveType(type);
            var existingClassName = existingType.Name;
            var existingNamespace = existingType.Namespace;
            var metaType = MetadataManager.GetManager().GetMetaTypes().SingleOrDefault(dt => dt.ClassName == existingClassName && dt.Namespace == existingNamespace);
 
            if (metaType == null) return null;
 
            var fields = metaType
                .Fields;
 
            return fields;
        }

Wecan use this code inside a simple .aspx page with a button to execute, or add it to an e.g. helper library.

To call the method, it will look something like this:

RegisterFieldForUserProfile<ProjectSelectorElement>("Telerik.Sitefinity.Security.Model.SitefinityProfile", "Projects");

So when this is executed, the new field is created and we now have our project selector added to the user profile.

Sitefinity Dynamic Project selector

So there we have our solution. Thanks to Atanas Valchev  for helping me with this.

Check out this weblog or sitefinity.com if you need more help and resources.

door Daniel Plomp

Reactie

RadEditor - HTML WYSIWYG Editor. MS Word-like content editing experience thanks to a rich set of formatting tools, dropdowns, dialogs, system modules and built-in spell-check.
RadEditor's components - toolbar, content area, modes and modules
   
Toolbar's wrapper 
 
Content area wrapper
RadEditor's bottom area: Design, Html and Preview modes, Statistics module and resize handle.
It contains RadEditor's Modes/views (HTML, Design and Preview), Statistics and Resizer
Editor Mode buttonsStatistics moduleEditor resizer
  
RadEditor's Modules - special tools used to provide extra information such as Tag Inspector, Real Time HTML Viewer, Tag Properties and other.