private async Task ApplyIndividualDefaultApplication(SecurityContractDefaultConfigurationApplication defaultApplication, Guid updatedById)
        {
            // Ensure that the application actually exists. Obtain all the application function relations too, as they will be used for validation.
            var application = await applicationRepository.GetByNameAsync(defaultApplication.Name);

            if (application == null)
            {
                logger.Warn($"Application '{defaultApplication.Name}' does not exist! Skipping and ignoring default application configuration for this application.");
                return;
            }

            if (defaultApplication.Functions == null || defaultApplication.Functions.Count == 0)
            {
                logger.Warn($"Default application '{defaultApplication.Name}' has no 'functions' configuration. Ignoring default configuration for this application.");
                return;
            }

            // Use the currrent state of the assigned application functions to determine which ones are potentially no longer in the YAML.
            await DetectFunctionsRemovedFromSecurityContractDefaultsAndRemoveFromApplication(application, defaultApplication.Functions);

            // Reset the state of the application functions, as the security contract declares the desired state and we have already used to the historic state
            // to clear any functions that don't appear within the security contract.
            application.Functions = new List <FunctionModel>();
            application.ChangedBy = updatedById;

            foreach (var defaultFunction in defaultApplication.Functions)
            {
                if (defaultFunction.Permissions == null || defaultFunction.Permissions.Count == 0)
                {
                    break;
                }

                var functionModelToAdd = new FunctionModel();
                // check to see if there is an existing function.
                var existingFunction = await functionRepository.GetByNameAsync(defaultFunction.Name);

                if (existingFunction != null)
                {
                    functionModelToAdd = existingFunction;
                }

                functionModelToAdd.Application = application;
                functionModelToAdd.Description = defaultFunction.Description;
                functionModelToAdd.Name        = defaultFunction.Name;
                functionModelToAdd.ChangedBy   = updatedById;

                // Clear the current permissions assigned to the function as they are to be re-created.
                functionModelToAdd.FunctionPermissions = new List <FunctionPermissionModel>();

                AddPermissionsToFunctionsEnsuringTheyExistsAndAreAssigedToTheApplication(application, defaultFunction, defaultApplication, functionModelToAdd, updatedById);
            }

            // Update the application with its new application function state.
            await applicationRepository.Update(application);
        }
        private async Task <List <SecurityContractDefaultConfigurationApplication> > RetrieveDefaultConfigApplications()
        {
            var contractAppList = new List <SecurityContractDefaultConfigurationApplication>();
            List <ApplicationModel> applications = await applicationRepository.GetListAsync();

            foreach (var application in applications.OrderBy(o => o.SysPeriod.LowerBound))
            {
                logger.Debug($"Retrieving default configuration contract definition for Application [{application.Name}].");

                var contractApplication = new SecurityContractDefaultConfigurationApplication()
                {
                    Name      = application.Name,
                    Functions = new List <SecurityContractDefaultConfigurationFunction>()
                };

                foreach (var function in application.Functions.OrderBy(o => o.SysPeriod.LowerBound))
                {
                    logger.Debug($"Retrieving default configuration contract definition for Function [{function.Name}].");

                    var contractFunction = new SecurityContractDefaultConfigurationFunction()
                    {
                        Name        = function.Name,
                        Description = function.Description,
                        Permissions = new List <string>()
                    };

                    foreach (var permission in function.FunctionPermissions.OrderBy(o => o.Permission.SysPeriod.LowerBound))
                    {
                        contractFunction.Permissions.Add(permission.Permission.Name);
                    }

                    contractApplication.Functions.Add(contractFunction);
                }

                contractAppList.Add(contractApplication);
            }

            return(contractAppList);
        }
        /// <summary>
        /// Adds permissions to an application function. However, before this is done, checks are run to ensure that the permissions is defined for the application by being present
        /// within at least one of the application functions (created by the micro-service).
        /// </summary>
        /// <param name="application"></param>
        /// <param name="defaultFunction"></param>
        /// <param name="defaultApplication"></param>
        /// <param name="functionModelToAdd"></param>
        private void AddPermissionsToFunctionsEnsuringTheyExistsAndAreAssigedToTheApplication(ApplicationModel application, SecurityContractDefaultConfigurationFunction defaultFunction,
                                                                                              SecurityContractDefaultConfigurationApplication defaultApplication, FunctionModel functionModelToAdd, Guid updatedById)
        {
            foreach (var permissionToAddToFunction in defaultFunction.Permissions)
            {
                bool permissionIsApplicationPermission = false;
                // Ensure the permission actually exists in at least one of the application functions. Only add the permission to the function if it does.
                if (application.ApplicationFunctions == null || application.ApplicationFunctions.Count == 0)
                {
                    logger.Warn($"Application '{defaultApplication.Name}' does not have any associated application functions!");
                    break;
                }

                foreach (var applicationFunction in application.ApplicationFunctions)
                {
                    var permission = applicationFunction.ApplicationFunctionPermissions.Find(afp => afp.Permission.Name == permissionToAddToFunction);
                    if (permission != null)
                    {
                        logger.Debug($"Assigning permission '{permissionToAddToFunction}' to function: '{functionModelToAdd.Name}'.");
                        permission.ChangedBy = updatedById;
                        permissionIsApplicationPermission = true;
                        functionModelToAdd.FunctionPermissions.Add(new FunctionPermissionModel
                        {
                            Function   = functionModelToAdd,
                            Permission = permission.Permission,
                            ChangedBy  = updatedById
                        });
                    }
                }

                if (!permissionIsApplicationPermission)
                {
                    logger.Warn($"Permission '{permissionToAddToFunction}' is not an existing application permission. Not adding it!");
                }
            }

            // Persist the application function, but only if there is at least a single permission associated with it.
            if (functionModelToAdd.FunctionPermissions.Count > 0)
            {
                logger.Debug($"Assigning function '{functionModelToAdd.Name}' to application '{application.Name}'");
                application.Functions.Add(functionModelToAdd);
            }
        }