public void FeatureDescriptorsAreInDependencyOrder()
        {
            var extensionLoader = new StubLoaders();
            var extensionFolder = new StubFolders();

            extensionFolder.Manifests.Add("Alpha", @"
Name: Alpha
Version: 1.0.3
OrchardVersion: 1
Features:
    Alpha:
        Dependencies: Gamma
");

            extensionFolder.Manifests.Add("Beta", @"
Name: Beta
Version: 1.0.3
OrchardVersion: 1
");
            extensionFolder.Manifests.Add("Gamma", @"
Name: Gamma
Version: 1.0.3
OrchardVersion: 1
Features:
    Gamma:
        Dependencies: Beta
");

            IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader);
            var features = extensionManager.AvailableFeatures();

            Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
        }
        private IEnumerable <string> GetFeatures()
        {
            var features =
                new[] { "Rabbit.Kernel" }.Concat(
                _extensionManager.AvailableFeatures().Select(i => i.Id)).ToArray();

            return(features);
        }
        private IEnumerable <string> GetFeatures()
        {
            var features =
                new[] { "SuperRocket.Framework" }.Concat(
                _extensionManager.AvailableFeatures().Select(i => i.Id)).ToArray();

            return(features);
        }
        public ShellBlueprint Compose(ShellSettings settings, ShellDescriptor descriptor)
        {
            Logger.Debug("Composing blueprint");

            var builtinFeatures           = BuiltinFeatures().ToList();
            var builtinFeatureDescriptors = builtinFeatures.Select(x => x.Descriptor).ToList();
            var availableFeatures         = _extensionManager.AvailableFeatures()
                                            .Concat(builtinFeatureDescriptors)
                                            .GroupBy(x => x.Id.ToLowerInvariant()) // prevent duplicates
                                            .Select(x => x.FirstOrDefault())
                                            .ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase);
            var enabledFeatures  = _extensionManager.EnabledFeatures(descriptor).Select(x => x.Id).ToList();
            var expandedFeatures = ExpandDependencies(availableFeatures, descriptor.Features.Select(x => x.Name)).ToList();
            var autoEnabledDependencyFeatures = expandedFeatures.Except(enabledFeatures).Except(builtinFeatureDescriptors.Select(x => x.Id)).ToList();
            var featureDescriptors            = _extensionManager.EnabledFeatures(expandedFeatures.Select(x => new ShellFeature {
                Name = x
            })).ToList();
            var features = _extensionManager.LoadFeatures(featureDescriptors);

            if (descriptor.Features.Any(feature => feature.Name == "Boying.Framework"))
            {
                features = builtinFeatures.Concat(features);
            }

            var excludedTypes   = GetExcludedTypes(features);
            var modules         = BuildBlueprint(features, IsModule, BuildModule, excludedTypes);
            var dependencies    = BuildBlueprint(features, IsDependency, (t, f) => BuildDependency(t, f, descriptor), excludedTypes);
            var controllers     = BuildBlueprint(features, IsController, BuildController, excludedTypes);
            var httpControllers = BuildBlueprint(features, IsHttpController, BuildController, excludedTypes);
            var records         = BuildBlueprint(features, IsRecord, (t, f) => BuildRecord(t, f, settings), excludedTypes);

            var result = new ShellBlueprint
            {
                Settings        = settings,
                Descriptor      = descriptor,
                Dependencies    = dependencies.Concat(modules).ToArray(),
                Controllers     = controllers,
                HttpControllers = httpControllers,
                Records         = records,
            };

            Logger.Debug("Done composing blueprint.");

            if (autoEnabledDependencyFeatures.Any())
            {
                // Add any dependencies previously not enabled to the shell descriptor.
                descriptor.Features = descriptor.Features.Concat(autoEnabledDependencyFeatures.Select(x => new ShellFeature {
                    Name = x
                })).ToList();
                Logger.Information("Automatically enabled the following dependency features: {0}.", String.Join(", ", autoEnabledDependencyFeatures));
            }

            return(result);
        }
예제 #5
0
        public void Discover(ShapeTableBuilder builder)
        {
            var availableFeatures = _extensionManager.AvailableFeatures();
            var activeFeatures    = availableFeatures.Where(fd => FeatureIsTheme(fd) || FeatureIsEnabled(fd));
            var activeExtensions  = Once(activeFeatures);

            foreach (var featureDescriptor in activeExtensions.SelectMany(extensionDescriptor => extensionDescriptor.Descriptor.Features.Where(fd => fd.Id == fd.Extension.Id)))
            {
                ProcessFeatureDescriptor(builder, featureDescriptor);
            }
        }
예제 #6
0
        void CreateAndActivateShells()
        {
            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Start creation of shells");
            }

            // Load all extensions and features so that the controllers are
            // registered in ITypeFeatureProvider and their areas definedin the application
            // conventions.
            _extensionManager.LoadFeatures(_extensionManager.AvailableFeatures());

            // Is there any tenant right now?
            var allSettings = _shellSettingsManager.LoadSettings()
                              .Where(settings =>
                                     settings.State == TenantState.Running ||
                                     settings.State == TenantState.Uninitialized ||
                                     settings.State == TenantState.Initializing)
                              .ToArray();

            // Load all tenants, and activate their shell.
            if (allSettings.Any())
            {
                Parallel.ForEach(allSettings, settings =>
                {
                    try
                    {
                        var context = CreateShellContext(settings);
                        ActivateShell(context);
                    }
                    catch (Exception ex)
                    {
                        if (ex.IsFatal())
                        {
                            throw;
                        }

                        _logger.LogError(string.Format("A tenant could not be started: {0}", settings.Name), ex);
                    }
                });
            }
            // No settings, run the Setup.
            else
            {
                var setupContext = CreateSetupContext();
                ActivateShell(setupContext);
            }

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Done creating shells");
            }
        }
예제 #7
0
        /// <summary>
        /// 获取开启的特性。
        /// </summary>
        /// <param name="extensionManager">扩展管理者。</param>
        /// <param name="descriptor">外壳描述符。</param>
        /// <returns></returns>
        public static IEnumerable <FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor)
        {
            extensionManager.NotNull("extensionManager");

            var features = extensionManager.AvailableFeatures();

            if (descriptor != null)
            {
                features = features.Where(fd => descriptor.Features.Any(sf => sf.Name == fd.Id));
            }

            return(features.ToArray());
        }
예제 #8
0
        public ActionResult Index()
        {
            var availableFeatures = _extensionManager.AvailableFeatures().Select(i => i.Id).ToArray();
            var currentFeatures   = _shellDescriptor.Features.Select(i => i.Name).ToArray();

            var model = availableFeatures.Select(i => new FeatureViewModel
            {
                Name   = i,
                Enable = currentFeatures.Contains(i)
            }).ToArray();

            return(View(model));
        }
예제 #9
0
        private IEnumerable <ExtensionDescriptor> GetBaseThemes(ExtensionDescriptor themeExtension)
        {
            if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase))
            {
                // Special case: conceptually, the base themes of "TheAdmin" is the list of all
                // enabled themes. This is so that any enabled theme can have controller/action/views
                // in the Admin of the site.
                return(_extensionManager
                       .EnabledFeatures(_shellDescriptor)
                       .Reverse() // reverse from (C <= B <= A) to (A => B => C)
                       .Select(fd => fd.Extension)
                       .Where(fd => DefaultExtensionTypes.IsTheme(fd.ExtensionType)));
            }
            else
            {
                var availableFeatures = _extensionManager.AvailableFeatures();
                var list = new List <ExtensionDescriptor>();
                while (true)
                {
                    if (themeExtension == null)
                    {
                        break;
                    }

                    if (String.IsNullOrEmpty(themeExtension.BaseTheme))
                    {
                        break;
                    }

                    var baseFeature = availableFeatures.FirstOrDefault(fd => fd.Id == themeExtension.BaseTheme);
                    if (baseFeature == null)
                    {
                        Logger.Error("Base theme '{0}' of theme '{1}' not found in list of features", themeExtension.BaseTheme, themeExtension.Id);
                        break;
                    }

                    // Protect against potential infinite loop
                    if (list.Contains(baseFeature.Extension))
                    {
                        Logger.Error("Base theme '{0}' of theme '{1}' ignored, as it seems there is recursion in base themes", themeExtension.BaseTheme, themeExtension.Id);
                        break;
                    }

                    list.Add(baseFeature.Extension);

                    themeExtension = baseFeature.Extension;
                }
                return(list);
            }
        }
        public Task <ShellDescriptor> GetShellDescriptorAsync()
        {
            if (_shellDescriptor == null)
            {
                _shellDescriptor = new ShellDescriptor
                {
                    Features = _extensionManager.AvailableFeatures().Select(x => new ShellFeature {
                        Name = x.Id
                    }).ToList()
                };
            }

            return(Task.FromResult(_shellDescriptor));
        }
예제 #11
0
        public void Discover(ShapeTableBuilder builder)
        {
            var availableFeatures = _extensionManager.AvailableFeatures();
            var activeFeatures    = availableFeatures.Where(FeatureIsEnabled);
            var activeExtensions  = Once(activeFeatures);

            var hits = activeExtensions.SelectMany(extensionDescriptor =>
            {
                var basePath    = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
                var virtualPath = Path.Combine(basePath, GetFolder()).Replace(Path.DirectorySeparatorChar, '/');
                var shapes      = _virtualPathProvider.ListFiles(virtualPath)
                                  .Select(Path.GetFileName)
                                  .Where(fileName => string.Equals(Path.GetExtension(fileName), GetFileExtension(), StringComparison.OrdinalIgnoreCase))
                                  .Select(cssFileName => new
                {
                    fileName        = Path.GetFileNameWithoutExtension(cssFileName),
                    fileVirtualPath = Path.Combine(virtualPath, cssFileName).Replace(Path.DirectorySeparatorChar, '/'),
                    shapeType       = GetShapePrefix() + GetAlternateShapeNameFromFileName(cssFileName),
                    extensionDescriptor
                });
                return(shapes);
            });

            foreach (var iter in hits)
            {
                var hit = iter;
                var featureDescriptors = hit.extensionDescriptor.Features.Where(fd => fd.Id == hit.extensionDescriptor.Id);
                foreach (var featureDescriptor in featureDescriptors)
                {
                    builder.Describe(iter.shapeType)
                    .From(new Feature {
                        Descriptor = featureDescriptor
                    })
                    .BoundAs(
                        hit.fileVirtualPath,
                        shapeDescriptor => displayContext =>
                    {
                        var shape  = ((dynamic)displayContext.Value);
                        var output = displayContext.ViewContext.Writer;
                        ResourceDefinition resource            = shape.Resource;
                        string condition                       = shape.Condition;
                        Dictionary <string, string> attributes = shape.TagAttributes;
                        ResourceManager.WriteResource(output, resource, hit.fileVirtualPath, condition, attributes);
                        return(null);
                    });
                }
            }
        }
        public IEnumerable <string> HarvestReactEnabledModules()
        {
            var availableFeatures    = _extensionManager.AvailableFeatures();
            var activeFeatures       = availableFeatures.Where(FeatureIsEnabled);
            var activeExtensions     = Once(activeFeatures).ToList();
            var modulesWithReactCode = _parallelCacheContext.RunInParallel(activeExtensions, extensionDescriptor => {
                var containsReact = ReactFolderPaths().Select(folderPath => {
                    var basePath    = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
                    var virtualPath = Path.Combine(basePath, folderPath).Replace(Path.DirectorySeparatorChar, '/');
                    return(_virtualPathProvider.DirectoryExists(virtualPath) ? virtualPath : null);
                }).Where(x => x != null).ToList();
                return(containsReact.Count > 0 ? containsReact.FirstOrDefault() : null);
            }).Where(x => x != null).ToList();

            return(modulesWithReactCode);
        }
예제 #13
0
        private IEnumerable <ExtensionDescriptorEntry> GetBaseThemes(ExtensionDescriptorEntry themeExtension)
        {
            //TODO:这边需要重新考虑

            /*if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase))
             * {
             *  return _extensionManager
             *      .EnabledFeatures(_shellDescriptor)
             *      .Reverse()
             *      .Select(fd => fd.Extension)
             *      .Where(fd => DefaultExtensionTypes.IsTheme(fd.ExtensionType));
             * }*/
            var availableFeatures = _extensionManager.AvailableFeatures().ToArray();
            var list = new List <ExtensionDescriptorEntry>();

            while (true)
            {
                if (themeExtension == null)
                {
                    break;
                }

                if (String.IsNullOrEmpty(themeExtension.Descriptor.GetBaseTheme()))
                {
                    break;
                }

                var baseFeature = availableFeatures.FirstOrDefault(fd => fd.Id == themeExtension.Descriptor.GetBaseTheme());
                if (baseFeature == null)
                {
                    Logger.Error("在 '{1}' 功能列表中找不到基础主题 '{0}'", themeExtension.Descriptor.GetBaseTheme(), themeExtension.Id);
                    break;
                }

                //防止潜在的无限循环
                if (list.Contains(baseFeature.Extension))
                {
                    Logger.Error("主题 '{1}' 是基础主题 '{0}' 所以被忽略", themeExtension.Descriptor.GetBaseTheme(), themeExtension.Id);
                    break;
                }

                list.Add(baseFeature.Extension);

                themeExtension = baseFeature.Extension;
            }
            return(list);
        }
        public void FeatureDescriptorsShouldBeLoadedInThemes()
        {
            var extensionLoader       = new StubLoaders();
            var moduleExtensionFolder = new StubFolders();
            var themeExtensionFolder  = new StubFolders(DefaultExtensionTypes.Theme);

            moduleExtensionFolder.Manifests.Add("Alpha", @"
Name: Alpha
Version: 1.0.3
SystemVersion: 1
Features:
    Alpha:
        Dependencies: Gamma
");

            moduleExtensionFolder.Manifests.Add("Beta", @"
Name: Beta
Version: 1.0.3
SystemVersion: 1
");
            moduleExtensionFolder.Manifests.Add("Gamma", @"
Name: Gamma
Version: 1.0.3
SystemVersion: 1
Features:
    Gamma:
        Dependencies: Beta
");

            themeExtensionFolder.Manifests.Add("Classic", @"
Name: Classic
Version: 1.0.3
SystemVersion: 1
");

            IExtensionManager extensionManager =
                CreateExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader });
            var features = extensionManager.AvailableFeatures();

            Assert.Equal(features.Count(), 4);
        }
        private bool IsBaseTheme(string featureName, string themeName)
        {
            // determine if the given feature is a base theme of the given theme
            var availableFeatures = _extensionManager.AvailableFeatures();

            var themeFeature = availableFeatures.SingleOrDefault(fd => fd.Id == themeName);

            while (themeFeature != null)
            {
                var baseTheme = themeFeature.Extension.BaseTheme;
                if (string.IsNullOrEmpty(baseTheme))
                {
                    return(false);
                }
                if (featureName == baseTheme)
                {
                    return(true);
                }
                themeFeature = availableFeatures.SingleOrDefault(fd => fd.Id == baseTheme);
            }
            return(false);
        }
        public void FeatureDescriptorsShouldBeLoadedInThemes()
        {
            var extensionLoader       = new StubLoaders();
            var moduleExtensionFolder = new StubExtensionLocator(new [] { DefaultExtensionTypes.Module, DefaultExtensionTypes.Theme });

            moduleExtensionFolder.Manifests.Add("Alpha", @"
Name: Alpha
Version: 1.0.3
OrchardVersion: 1
Features:
    Alpha:
        Dependencies: Gamma
");

            moduleExtensionFolder.Manifests.Add("Beta", @"
Name: Beta
Version: 1.0.3
OrchardVersion: 1
");
            moduleExtensionFolder.Manifests.Add("Gamma", @"
Name: Gamma
Version: 1.0.3
OrchardVersion: 1
Features:
    Gamma:
        Dependencies: Beta
");

            moduleExtensionFolder.ThemeManifests.Add("Classic", @"
Name: Classic
Version: 1.0.3
OrchardVersion: 1
");

            IExtensionManager extensionManager = CreateExtensionManager(moduleExtensionFolder, new[] { extensionLoader });
            var features = extensionManager.AvailableFeatures();

            Assert.Equal(4, features.Count());
        }
예제 #17
0
        private bool IsBaseTheme(string featureName, string themeName)
        {
            //判断给定的功能是给定主题的基本主题
            var availableFeatures = _extensionManager.AvailableFeatures().ToArray();

            var themeFeature = availableFeatures.SingleOrDefault(fd => fd.Id == themeName);

            while (themeFeature != null)
            {
                var baseTheme = themeFeature.Extension.Descriptor.GetBaseTheme();
                if (String.IsNullOrEmpty(baseTheme))
                {
                    return(false);
                }
                if (featureName == baseTheme)
                {
                    return(true);
                }
                themeFeature = availableFeatures.SingleOrDefault(fd => fd.Id == baseTheme);
            }
            return(false);
        }
예제 #18
0
        public void Discover(ShapeTableBuilder builder)
        {
            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Start discovering shapes");
            }
            var harvesterInfos = _harvesters.Select(harvester => new { harvester, subPaths = harvester.SubPaths() });

            var availableFeatures = _extensionManager.AvailableFeatures();
            var activeFeatures    = availableFeatures.Where(FeatureIsEnabled);
            var activeExtensions  = Once(activeFeatures);

            var hits = activeExtensions.Select(extensionDescriptor =>
            {
                if (_logger.IsEnabled(LogLevel.Information))
                {
                    _logger.LogInformation("Start discovering candidate views filenames");
                }
                var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath =>
                {
                    var basePath    = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
                    var virtualPath = Path.Combine(basePath, subPath).Replace(Path.DirectorySeparatorChar, '/');
                    IReadOnlyList <string> fileNames;

                    if (!_virtualPathProvider.DirectoryExists(virtualPath))
                    {
                        fileNames = new List <string>();
                    }
                    else
                    {
                        fileNames = _virtualPathProvider.ListFiles(virtualPath).Select(Path.GetFileName).ToReadOnlyCollection();
                    }

                    return(new { harvesterInfo.harvester, basePath, subPath, virtualPath, fileNames });
                })).ToList();
                if (_logger.IsEnabled(LogLevel.Information))
                {
                    _logger.LogInformation("Done discovering candidate views filenames");
                }
                var fileContexts = pathContexts.SelectMany(pathContext => _shapeTemplateViewEngines.SelectMany(ve =>
                {
                    var fileNames = ve.DetectTemplateFileNames(pathContext.fileNames);
                    return(fileNames.Select(
                               fileName => new
                    {
                        fileName = Path.GetFileNameWithoutExtension(fileName),
                        fileVirtualPath = Path.Combine(pathContext.virtualPath, fileName).Replace(Path.DirectorySeparatorChar, '/'),
                        pathContext
                    }));
                }));

                var shapeContexts = fileContexts.SelectMany(fileContext =>
                {
                    var harvestShapeInfo = new HarvestShapeInfo
                    {
                        SubPath             = fileContext.pathContext.subPath,
                        FileName            = fileContext.fileName,
                        TemplateVirtualPath = fileContext.fileVirtualPath
                    };
                    var harvestShapeHits = fileContext.pathContext.harvester.HarvestShape(harvestShapeInfo);
                    return(harvestShapeHits.Select(harvestShapeHit => new { harvestShapeInfo, harvestShapeHit, fileContext }));
                });

                return(shapeContexts.Select(shapeContext => new { extensionDescriptor, shapeContext }).ToList());
            }).SelectMany(hits2 => hits2);


            foreach (var iter in hits)
            {
                // templates are always associated with the namesake feature of module or theme
                var hit = iter;
                var featureDescriptors = iter.extensionDescriptor.Features.Where(fd => fd.Id == hit.extensionDescriptor.Id);
                foreach (var featureDescriptor in featureDescriptors)
                {
                    if (_logger.IsEnabled(LogLevel.Debug))
                    {
                        _logger.LogDebug("Binding {0} as shape [{1}] for feature {2}",
                                         hit.shapeContext.harvestShapeInfo.TemplateVirtualPath,
                                         iter.shapeContext.harvestShapeHit.ShapeType,
                                         featureDescriptor.Id);
                    }
                    builder.Describe(iter.shapeContext.harvestShapeHit.ShapeType)
                    .From(new Feature {
                        Descriptor = featureDescriptor
                    })
                    .BoundAs(
                        hit.shapeContext.harvestShapeInfo.TemplateVirtualPath,
                        shapeDescriptor => displayContext => RenderAsync(shapeDescriptor, displayContext, hit.shapeContext.harvestShapeInfo, hit.shapeContext.harvestShapeHit));
                }
            }

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Done discovering shapes");
            }
        }
 public static IEnumerable <FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor)
 {
     return(extensionManager.AvailableFeatures());
 }
        public void Update(string feature)
        {
            if (_processedFeatures.Contains(feature))
            {
                return;
            }

            _processedFeatures.Add(feature);

            Logger.Information("Updating feature: {0}", feature);

            // proceed with dependent features first, whatever the module it's in
            var dependencies = _extensionManager.AvailableFeatures()
                               .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase))
                               .Where(f => f.Dependencies != null)
                               .SelectMany(f => f.Dependencies)
                               .ToList();

            foreach (var dependency in dependencies)
            {
                Update(dependency);
            }

            var migrations = GetDataMigrations(feature);

            // apply update methods to each migration class for the module
            foreach (var migration in migrations)
            {
                // copy the object for the Linq query
                var tempMigration = migration;

                // get current version for this migration
                var dataMigrationRecord = GetDataMigrationRecord(tempMigration);

                var current = 0;
                if (dataMigrationRecord != null)
                {
                    current = dataMigrationRecord.Version.Value;
                }

                try {
                    _transactionManager.RequireNew();

                    // do we need to call Create() ?
                    if (current == 0)
                    {
                        // try to resolve a Create method

                        var createMethod = GetCreateMethod(migration);
                        if (createMethod != null)
                        {
                            current = (int)createMethod.Invoke(migration, new object[0]);
                        }
                    }

                    var lookupTable = CreateUpgradeLookupTable(migration);

                    while (lookupTable.ContainsKey(current))
                    {
                        try {
                            Logger.Information("Applying migration for {0} from version {1}", feature, current);
                            current = (int)lookupTable[current].Invoke(migration, new object[0]);
                        }
                        catch (Exception ex) {
                            Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}", feature, current);
                            throw;
                        }
                    }

                    // if current is 0, it means no upgrade/create method was found or succeeded
                    if (current == 0)
                    {
                        continue;
                    }
                    if (dataMigrationRecord == null)
                    {
                        _dataMigrationRepository.Create(new DataMigrationRecord {
                            Version = current, DataMigrationClass = migration.GetType().FullName
                        });
                    }
                    else
                    {
                        dataMigrationRecord.Version = current;
                    }
                }
                catch (Exception e) {
                    Logger.Error(e, "Error while running migration version {0} for {1}", current, feature);
                    _transactionManager.Cancel();
                }
            }
        }
예제 #21
0
        public ActionResult Features()
        {
            if (!CheckPermission(DashboardPermissions.ManageModules))
            {
                return(new HttpUnauthorizedResult());
            }

            WorkContext.Breadcrumbs.Add(T("Modules"));
            WorkContext.Breadcrumbs.Add(T("Features"));

            var features   = extensionManager.AvailableFeatures().Where(x => !DefaultExtensionTypes.IsTheme(x.Extension.ExtensionType)).ToList();
            var groups     = features.GroupBy(x => x.Category).OrderBy(x => x.Key);
            var htmlHelper = new HtmlHelper(new ViewContext(), new ViewDataContainer(ViewData));
            var sb         = new StringBuilder();

            foreach (var @group in groups)
            {
                sb.AppendFormat("<h3>{0}</h3>", string.IsNullOrEmpty(group.Key) ? "Uncategorized" : group.Key);
                foreach (var descriptor in group.OrderBy(x => x.Name))
                {
                    if (descriptor.Name.Equals("CMS") || descriptor.Name.Equals("Security"))
                    {
                        continue;
                    }
                    var missingDependencies = descriptor.Dependencies.Where(d => !features.Any(f => f.Id.Equals(d, StringComparison.OrdinalIgnoreCase))).ToList();
                    var showDisable         = @group.Key != "Core";
                    var showEnable          = !missingDependencies.Any();
                    var enabled             = shellDescriptor.Features.Any(x => x.Name == descriptor.Id);

                    sb.AppendFormat("<div class=\"{1}\"><div class=\"well well-small feature\" id=\"{0}-feature\">", descriptor.Id.Replace(".", "-").ToSlugUrl(), Constants.ContainerCssClassCol3);
                    sb.AppendFormat("<h4>{0}</h4>", descriptor.Name);

                    sb.Append("<div class=\"actions\">");

                    if (showDisable && enabled)
                    {
                        sb.AppendFormat("<form action=\"{0}\" method=\"post\">", Url.Action("Disable"));
                        sb.AppendFormat("<input type=\"hidden\" name=\"id\" value=\"{0}\" />", descriptor.Id);
                        sb.Append(htmlHelper.AntiForgeryToken());
                        sb.AppendFormat("<button type=\"submit\" class=\"btn btn-link btn-disable-feature\">{0}</button>", T("Disable"));
                        sb.Append("</form>");
                    }

                    if (showEnable && !enabled)
                    {
                        sb.AppendFormat("<form action=\"{0}\" method=\"post\">", Url.Action("Enable"));
                        sb.AppendFormat("<input type=\"hidden\" name=\"id\" value=\"{0}\" />", descriptor.Id);
                        sb.Append(htmlHelper.AntiForgeryToken());
                        sb.AppendFormat("<button type=\"submit\" class=\"btn btn-link btn-enable-feature\">{0}</button>", T("Enable"));
                        sb.Append("</form>");
                    }

                    sb.Append("</div>");

                    var dependencies = (from d in descriptor.Dependencies
                                        select(from f in features where f.Id.Equals(d, StringComparison.OrdinalIgnoreCase) select f).SingleOrDefault()).Where(f => f != null).OrderBy(f => f.Name);
                    if (!dependencies.IsNullOrEmpty())
                    {
                        sb.Append("<div class=\"dependencies\">");
                        sb.AppendFormat("<strong>{0}:</strong>", T("Depends on"));
                        sb.Append("<ul class=\"list-unstyled inline\">");

                        foreach (var dependency in dependencies)
                        {
                            sb.AppendFormat("<li><a href=\"#{1}-feature\">{0}</a></li>", dependency.Name, dependency.Id.Replace(".", "-").ToSlugUrl());
                        }

                        sb.Append("</ul>");
                        sb.Append("</div>");
                    }

                    if (!missingDependencies.IsNullOrEmpty())
                    {
                        sb.Append("<div class=\"missing-dependencies\">");
                        sb.AppendFormat("<strong>{0}:</strong>", T("Missing"));
                        sb.Append("<ul class=\"list-unstyled inline\">");

                        foreach (var dependency in missingDependencies)
                        {
                            sb.AppendFormat("<li>{0}</li>", dependency);
                        }

                        sb.Append("</ul>");
                        sb.Append("</div>");
                    }

                    sb.Append("</div></div>");
                }

                sb.Append("<div class='clearfix'></div>");
            }

            return(new ControlContentResult(sb.ToString())
            {
                Title = T("Modules")
            });
        }
예제 #22
0
 /// <summary>
 /// Retrieves the available features.
 /// </summary>
 /// <returns>An enumeration of feature descriptors for the available features.</returns>
 public IEnumerable <FeatureDescriptor> GetAvailableFeatures()
 {
     return(_extensionManager.AvailableFeatures());
 }
예제 #23
0
 /// <summary>
 /// Retrieves the available features.
 /// </summary>
 /// <returns>An enumeration of feature descriptors for the available features.</returns>
 public Task <IEnumerable <FeatureDescriptor> > GetAvailableFeaturesAsync()
 {
     return(Task.FromResult(_extensionManager.AvailableFeatures()));
 }
예제 #24
0
 public static IEnumerable <FeatureDescriptor> DisabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor)
 {
     return(extensionManager.AvailableFeatures().Where(fd => descriptor.Features.All(sf => sf.Name != fd.Id)));
 }
예제 #25
0
 public static IEnumerable <FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, IEnumerable <ShellFeature> features)
 {
     return(extensionManager.AvailableFeatures().Where(fd => features.Any(sf => sf.Name == fd.Id)));
 }
예제 #26
0
        void IShellStateManagerEventHandler.ApplyChanges()
        {
            Logger.Information("Applying changes for for shell '{0}'", _settings.Name);

            var shellState = _stateManager.GetShellState();

            // start with description of all declared features in order - order preserved with all merging
            var orderedFeatureDescriptors = _extensionManager.AvailableFeatures();

            // merge feature state into ordered list
            var orderedFeatureDescriptorsAndStates = orderedFeatureDescriptors
                                                     .Select(featureDescriptor => new
            {
                FeatureDescriptor = featureDescriptor,
                FeatureState      = shellState.Features.FirstOrDefault(s => s.Name == featureDescriptor.Id),
            })
                                                     .Where(entry => entry.FeatureState != null)
                                                     .ToArray();

            // get loaded feature information
            var loadedFeatures = _extensionManager.LoadFeatures(orderedFeatureDescriptorsAndStates.Select(entry => entry.FeatureDescriptor)).ToArray();

            // merge loaded feature information into ordered list
            var loadedEntries = orderedFeatureDescriptorsAndStates.Select(
                entry => new
            {
                Feature = loadedFeatures.SingleOrDefault(f => f.Descriptor == entry.FeatureDescriptor)
                          ?? new Feature
                {
                    Descriptor    = entry.FeatureDescriptor,
                    ExportedTypes = Enumerable.Empty <Type>()
                },
                entry.FeatureDescriptor,
                entry.FeatureState,
            }).ToList();

            // find feature state that is beyond what's currently available from modules
            var additionalState = shellState.Features.Except(loadedEntries.Select(entry => entry.FeatureState));

            // create additional stub entries for the sake of firing state change events on missing features
            var allEntries = loadedEntries.Concat(additionalState.Select(featureState =>
            {
                var featureDescriptor = new FeatureDescriptor
                {
                    Id        = featureState.Name,
                    Extension = new ExtensionDescriptor
                    {
                        Id = featureState.Name
                    }
                };
                return(new
                {
                    Feature = new Feature
                    {
                        Descriptor = featureDescriptor,
                        ExportedTypes = Enumerable.Empty <Type>(),
                    },
                    FeatureDescriptor = featureDescriptor,
                    FeatureState = featureState
                });
            })).ToArray();

            // lower enabled states in reverse order
            foreach (var entry in allEntries.Reverse().Where(entry => entry.FeatureState.EnableState == ShellFeatureState.State.Falling))
            {
                Logger.Information("Disabling feature '{0}'", entry.Feature.Descriptor.Id);
                _featureEvents.Disabling(entry.Feature);
                _stateManager.UpdateEnabledState(entry.FeatureState, ShellFeatureState.State.Down);
                _featureEvents.Disabled(entry.Feature);
            }

            // lower installed states in reverse order
            foreach (var entry in allEntries.Reverse().Where(entry => entry.FeatureState.InstallState == ShellFeatureState.State.Falling))
            {
                Logger.Information("Uninstalling feature '{0}'", entry.Feature.Descriptor.Id);
                _featureEvents.Uninstalling(entry.Feature);
                _stateManager.UpdateInstalledState(entry.FeatureState, ShellFeatureState.State.Down);
                _featureEvents.Uninstalled(entry.Feature);
            }

            // raise install and enabled states in order
            foreach (var entry in allEntries.Where(entry => IsRising(entry.FeatureState)))
            {
                if (entry.FeatureState.InstallState == ShellFeatureState.State.Rising)
                {
                    Logger.Information("Installing feature '{0}'", entry.Feature.Descriptor.Id);
                    _featureEvents.Installing(entry.Feature);
                    _stateManager.UpdateInstalledState(entry.FeatureState, ShellFeatureState.State.Up);
                    _featureEvents.Installed(entry.Feature);
                }
                if (entry.FeatureState.EnableState == ShellFeatureState.State.Rising)
                {
                    Logger.Information("Enabling feature '{0}'", entry.Feature.Descriptor.Id);
                    _featureEvents.Enabling(entry.Feature);
                    _stateManager.UpdateEnabledState(entry.FeatureState, ShellFeatureState.State.Up);
                    _featureEvents.Enabled(entry.Feature);
                }
            }

            // re-fire if any event handlers initiated additional state changes
            FireApplyChangesIfNeeded();
        }
//        public static IEnumerable<FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) {
//            return EnabledFeatures(extensionManager, descriptor.Features);
//        }
//
//        public static IEnumerable<FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, IEnumerable<ShellFeature> features) {
//            return extensionManager.AvailableFeatures().Where(fd => features.Any(sf => sf.Name == fd.Id));
//        }
//
//        public static IEnumerable<FeatureDescriptor> DisabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) {
//            return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.All(sf => sf.Name != fd.Id));
//        }

        public static IEnumerable <FeatureDescriptor> EnabledFeatures(this IExtensionManager extensionManager, string shellName)
        {
            return(extensionManager.AvailableFeatures().Where(fd => shellName == fd.Name));
        }
예제 #28
0
        public async Task UpdateAsync(string feature)
        {
            if (_processedFeatures.Contains(feature))
            {
                return;
            }

            _processedFeatures.Add(feature);

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Updating feature: {0}", feature);
            }

            // proceed with dependent features first, whatever the module it's in
            var dependencies = _extensionManager.AvailableFeatures()
                               .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase))
                               .Where(f => f.Dependencies != null)
                               .SelectMany(f => f.Dependencies)
                               .ToList();

            foreach (var dependency in dependencies)
            {
                await UpdateAsync(dependency);
            }

            var migrations = GetDataMigrations(feature);

            // apply update methods to each migration class for the module
            foreach (var migration in migrations)
            {
                _session.ExecuteMigration(schemaBuilder =>
                {
                    migration.SchemaBuilder = schemaBuilder;

                    // copy the object for the Linq query
                    var tempMigration = migration;

                    // get current version for this migration
                    var dataMigrationRecord = GetDataMigrationRecordAsync(tempMigration).Result;

                    var current = 0;
                    if (dataMigrationRecord != null)
                    {
                        current = dataMigrationRecord.Version.Value;
                    }
                    else
                    {
                        dataMigrationRecord = new DataMigration {
                            DataMigrationClass = migration.GetType().FullName
                        };
                        _dataMigrationRecord.DataMigrations.Add(dataMigrationRecord);
                    }

                    try
                    {
                        // do we need to call Create() ?
                        if (current == 0)
                        {
                            // try to resolve a Create method

                            var createMethod = GetCreateMethod(migration);
                            if (createMethod != null)
                            {
                                current = (int)createMethod.Invoke(migration, new object[0]);
                            }
                        }

                        var lookupTable = CreateUpgradeLookupTable(migration);

                        while (lookupTable.ContainsKey(current))
                        {
                            try
                            {
                                if (_logger.IsEnabled(LogLevel.Information))
                                {
                                    _logger.LogInformation("Applying migration for {0} from version {1}.", feature, current);
                                }
                                current = (int)lookupTable[current].Invoke(migration, new object[0]);
                            }
                            catch (Exception ex)
                            {
                                if (ex.IsFatal())
                                {
                                    throw;
                                }
                                _logger.LogError(0, "An unexpected error occurred while applying migration on {0} from version {1}.", feature, current);
                                throw;
                            }
                        }

                        // if current is 0, it means no upgrade/create method was found or succeeded
                        if (current == 0)
                        {
                            return;
                        }

                        dataMigrationRecord.Version = current;
                    }
                    catch (Exception ex)
                    {
                        if (ex.IsFatal())
                        {
                            throw;
                        }
                        _logger.LogError(0, "Error while running migration version {0} for {1}.", current, feature);
                        _session.Cancel();
                        throw new OrchardException(T("Error while running migration version {0} for {1}.", current, feature), ex);
                    }
                    finally
                    {
                        // Persist data migrations
                        _session.Save(_dataMigrationRecord);
                    }
                });
            }
        }
예제 #29
0
        /// <summary>
        /// Generates SchemaCommand instances in order to create the schema for a specific feature
        /// </summary>
        public IEnumerable <SchemaCommand> GetCreateFeatureCommands(string feature, bool drop)
        {
            var dependencies = _extensionManager.AvailableFeatures()
                               .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase))
                               .Where(f => f.Dependencies != null)
                               .SelectMany(f => f.Dependencies)
                               .ToList();

            var shellDescriptor = new ShellDescriptor {
                Features = dependencies.Select(id => new ShellFeature {
                    Name = id
                }).Union(new[] { new ShellFeature {
                                     Name = feature
                                 }, new ShellFeature {
                                     Name = "Orchard.Framework"
                                 } })
            };

            var shellBlueprint = _compositionStrategy.Compose(_shellSettings, shellDescriptor);

            if (!shellBlueprint.Records.Any())
            {
                yield break;
            }

            //var features = dependencies.Select(name => new ShellFeature {Name = name}).Union(new[] {new ShellFeature {Name = feature}, new ShellFeature {Name = "Orchard.Framework"}});

            var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();

            parameters.RecordDescriptors = shellBlueprint.Records;

            var configuration = _dataServicesProviderFactory
                                .CreateProvider(parameters)
                                .BuildConfiguration(parameters);

            Dialect.GetDialect(configuration.Properties);
            var mapping = configuration.BuildMapping();

            // get the table mappings using reflection
            var tablesField = typeof(Configuration).GetField("tables", BindingFlags.Instance | BindingFlags.NonPublic);
            var tables      = ((IDictionary <string, Table>)tablesField.GetValue(configuration)).Values;

            string prefix = feature.Replace(".", "_") + "_";

            foreach (var table in tables.Where(t => parameters.RecordDescriptors.Any(rd => rd.Feature.Descriptor.Id == feature && rd.TableName == t.Name)))
            {
                string tableName     = table.Name;
                var    recordType    = parameters.RecordDescriptors.First(rd => rd.Feature.Descriptor.Id == feature && rd.TableName == tableName).Type;
                var    isContentPart = typeof(ContentPartRecord).IsAssignableFrom(recordType);

                if (tableName.StartsWith(prefix))
                {
                    tableName = tableName.Substring(prefix.Length);
                }

                if (drop)
                {
                    yield return(new DropTableCommand(tableName));
                }

                var command = new CreateTableCommand(tableName);

                foreach (var column in table.ColumnIterator)
                {
                    // create copies for local variables to be evaluated at the time the loop is called, and not lately when the la;bda is executed
                    var tableCopy  = table;
                    var columnCopy = column;

                    var sqlType = columnCopy.GetSqlTypeCode(mapping);
                    command.Column(column.Name, sqlType.DbType,
                                   action => {
                        if (tableCopy.PrimaryKey.Columns.Any(c => c.Name == columnCopy.Name))
                        {
                            action.PrimaryKey();

                            if (!isContentPart)
                            {
                                action.Identity();
                            }
                        }


                        if (columnCopy.IsLengthDefined() &&
                            new[] { DbType.StringFixedLength, DbType.String, DbType.AnsiString, DbType.AnsiStringFixedLength }.Contains(sqlType.DbType) &&
                            columnCopy.Length != Column.DefaultLength)
                        {
                            action.WithLength(columnCopy.Length);
                        }

                        if (columnCopy.IsPrecisionDefined())
                        {
                            action.WithPrecision((byte)columnCopy.Precision);
                            action.WithScale((byte)columnCopy.Scale);
                        }
                        if (columnCopy.IsNullable)
                        {
                            action.Nullable();
                        }

                        if (columnCopy.IsUnique)
                        {
                            action.Unique();
                        }

                        if (columnCopy.DefaultValue != null)
                        {
                            action.WithDefault(columnCopy.DefaultValue);
                        }
                    });
                }

                yield return(command);
            }
        }