protected async Task <User> CreateUser(string nameCandidate, string loginName, string email, string fullName,
                                               Action <Content> setProperties, CancellationToken cancellationToken)
        {
            var parentPath = string.IsNullOrEmpty(_options.ParentPath) ? "/Root/IMS/Public" : _options.ParentPath;
            var userType   = string.IsNullOrEmpty(_options.UserType) ? "User" : _options.UserType;

            var parent = RepositoryTools.CreateStructure(parentPath, "Domain") ??
                         await Content.LoadAsync(parentPath, cancellationToken).ConfigureAwait(false);

            // If a user with the same name exists, make sure we create
            // a new one and let the application deal with merging them later.
            var name = ContentNamingProvider.GetNameFromDisplayName(nameCandidate);

            if (Node.Exists(RepositoryPath.Combine(parent.Path, name)))
            {
                name = ContentNamingProvider.IncrementNameSuffixToLastName(name, parent.Id);
            }

            var user = Content.CreateNew(userType, parent.ContentHandler, name);

            user["LoginName"] = loginName;
            user["Email"]     = email;
            user["FullName"]  = string.IsNullOrEmpty(fullName) ? name : fullName;
            user.DisplayName  = string.IsNullOrEmpty(fullName) ? name : fullName;
            user["Enabled"]   = true;

            setProperties?.Invoke(user);

            user.Save();

            await AddUserToDefaultGroupsAsync(user.ContentHandler as User, cancellationToken).ConfigureAwait(false);

            return(user.ContentHandler as User);
        }
        public async Task <User> CreateProviderUserAsync(Content content, HttpContext context, string provider, string userId,
                                                         ClaimInfo[] claims, CancellationToken cancellationToken)
        {
            var parentPath = string.IsNullOrEmpty(DefaultParentPath) ? "/Root/IMS/Public" : DefaultParentPath;
            var userType   = string.IsNullOrEmpty(DefaultUserType) ? "User" : DefaultUserType;

            var parent = RepositoryTools.CreateStructure(parentPath, "Domain") ??
                         await Content.LoadAsync(parentPath, cancellationToken).ConfigureAwait(false);

            var fullName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? string.Empty;
            var email    = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value ?? string.Empty;

            // Fill the field with an initial JSON data containing a single provider data.
            // Later, if the user already exists, this field needs to be edited: the new id
            // should be inserted instead of overwriting the current value.
            var external = $"{{ \"{provider}\": {{ \"Id\": \"{userId}\", \"Completed\": false }} }}";

            // User content name will be the email.
            // Current behavior: if a user with the same name exists, make sure we create
            // a new one and let the application deal with merging them later.
            var name = ContentNamingProvider.GetNameFromDisplayName(email);

            if (Node.Exists(RepositoryPath.Combine(parent.Path, name)))
            {
                name = ContentNamingProvider.IncrementNameSuffixToLastName(name, parent.Id);
            }

            var user = Content.CreateNew(userType, parent.ContentHandler, name);

            user["ExternalUserProviders"] = external;
            user["Email"]    = email;
            user["FullName"] = fullName;
            user.DisplayName = fullName;

            user.Save();

            await AddUserToDefaultGroupsAsync(user.ContentHandler as User, cancellationToken).ConfigureAwait(false);

            return(user.ContentHandler as User);
        }