mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-27 04:19:04 +08:00
#5525: Added Category field to Recipe and updated default recipes with "Default" category.
Recipes are now ordered alphabetically, first by group then by name. Fixes #5525
This commit is contained in:
@@ -2,20 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Orchard.Localization;
|
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
using Orchard.Recipes.Models;
|
using Orchard.Recipes.Models;
|
||||||
|
|
||||||
namespace Orchard.Recipes.Services {
|
namespace Orchard.Recipes.Services {
|
||||||
public class RecipeParser : IRecipeParser {
|
public class RecipeParser : Component, IRecipeParser {
|
||||||
public RecipeParser() {
|
|
||||||
Logger = NullLogger.Instance;
|
|
||||||
T = NullLocalizer.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Localizer T { get; set; }
|
|
||||||
public ILogger Logger { get; set; }
|
|
||||||
|
|
||||||
public Recipe ParseRecipe(string recipeText) {
|
public Recipe ParseRecipe(string recipeText) {
|
||||||
var recipe = new Recipe();
|
var recipe = new Recipe();
|
||||||
|
|
||||||
@@ -23,12 +15,11 @@ namespace Orchard.Recipes.Services {
|
|||||||
throw new Exception("Recipe is empty");
|
throw new Exception("Recipe is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
XElement recipeTree = XElement.Parse(recipeText, LoadOptions.PreserveWhitespace);
|
var recipeTree = XElement.Parse(recipeText, LoadOptions.PreserveWhitespace);
|
||||||
|
|
||||||
var recipeSteps = new List<RecipeStep>();
|
var recipeSteps = new List<RecipeStep>();
|
||||||
|
|
||||||
foreach (var element in recipeTree.Elements()) {
|
foreach (var element in recipeTree.Elements()) {
|
||||||
// Recipe metadata
|
// Recipe metadata.
|
||||||
if (element.Name.LocalName == "Recipe") {
|
if (element.Name.LocalName == "Recipe") {
|
||||||
foreach (var metadataElement in element.Elements()) {
|
foreach (var metadataElement in element.Elements()) {
|
||||||
switch (metadataElement.Name.LocalName) {
|
switch (metadataElement.Name.LocalName) {
|
||||||
@@ -53,6 +44,9 @@ namespace Orchard.Recipes.Services {
|
|||||||
case "ExportUtc":
|
case "ExportUtc":
|
||||||
recipe.ExportUtc = !string.IsNullOrEmpty(metadataElement.Value) ? (DateTime?)XmlConvert.ToDateTime(metadataElement.Value, XmlDateTimeSerializationMode.Utc) : null;
|
recipe.ExportUtc = !string.IsNullOrEmpty(metadataElement.Value) ? (DateTime?)XmlConvert.ToDateTime(metadataElement.Value, XmlDateTimeSerializationMode.Utc) : null;
|
||||||
break;
|
break;
|
||||||
|
case "Category":
|
||||||
|
recipe.Category = metadataElement.Value;
|
||||||
|
break;
|
||||||
case "Tags":
|
case "Tags":
|
||||||
recipe.Tags = metadataElement.Value;
|
recipe.Tags = metadataElement.Value;
|
||||||
break;
|
break;
|
||||||
@@ -62,7 +56,7 @@ namespace Orchard.Recipes.Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recipe step
|
// Recipe step.
|
||||||
else {
|
else {
|
||||||
var recipeStep = new RecipeStep { Name = element.Name.LocalName, Step = element };
|
var recipeStep = new RecipeStep { Name = element.Name.LocalName, Step = element };
|
||||||
recipeSteps.Add(recipeStep);
|
recipeSteps.Add(recipeStep);
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.Environment;
|
using Orchard.Environment;
|
||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
using Orchard.Recipes.Models;
|
|
||||||
using Orchard.Setup.Services;
|
using Orchard.Setup.Services;
|
||||||
using Orchard.Setup.ViewModels;
|
using Orchard.Setup.ViewModels;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
@@ -44,7 +42,7 @@ namespace Orchard.Setup.Controllers {
|
|||||||
|
|
||||||
public ActionResult Index() {
|
public ActionResult Index() {
|
||||||
var initialSettings = _setupService.Prime();
|
var initialSettings = _setupService.Prime();
|
||||||
var recipes = OrderRecipes(_setupService.Recipes());
|
var recipes = _setupService.Recipes().ToList();
|
||||||
string recipeDescription = null;
|
string recipeDescription = null;
|
||||||
if (recipes.Count > 0) {
|
if (recipes.Count > 0) {
|
||||||
recipeDescription = recipes[0].Description;
|
recipeDescription = recipes[0].Description;
|
||||||
@@ -54,13 +52,11 @@ namespace Orchard.Setup.Controllers {
|
|||||||
// will take a while to finish (user inputting data and the setup process itself).
|
// will take a while to finish (user inputting data and the setup process itself).
|
||||||
// We use this opportunity to start a background task to "pre-compile" all the known
|
// We use this opportunity to start a background task to "pre-compile" all the known
|
||||||
// views in the app folder, so that the application is more reponsive when the user
|
// views in the app folder, so that the application is more reponsive when the user
|
||||||
// hits the homepage and admin screens for the first time.))
|
// hits the homepage and admin screens for the first time).
|
||||||
if (StringComparer.OrdinalIgnoreCase.Equals(initialSettings.Name, ShellSettings.DefaultName)) {
|
if (StringComparer.OrdinalIgnoreCase.Equals(initialSettings.Name, ShellSettings.DefaultName)) {
|
||||||
_viewsBackgroundCompilation.Start();
|
_viewsBackgroundCompilation.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
return IndexViewResult(new SetupViewModel {
|
return IndexViewResult(new SetupViewModel {
|
||||||
AdminUsername = "admin",
|
AdminUsername = "admin",
|
||||||
DatabaseIsPreconfigured = !string.IsNullOrEmpty(initialSettings.DataProvider),
|
DatabaseIsPreconfigured = !string.IsNullOrEmpty(initialSettings.DataProvider),
|
||||||
@@ -71,32 +67,32 @@ namespace Orchard.Setup.Controllers {
|
|||||||
|
|
||||||
[HttpPost, ActionName("Index")]
|
[HttpPost, ActionName("Index")]
|
||||||
public ActionResult IndexPOST(SetupViewModel model) {
|
public ActionResult IndexPOST(SetupViewModel model) {
|
||||||
// sets the setup request timeout to 10 minutes to give enough time to execute custom recipes.
|
// Sets the setup request timeout to 10 minutes to give enough time to execute custom recipes.
|
||||||
HttpContext.Server.ScriptTimeout = 600;
|
HttpContext.Server.ScriptTimeout = 600;
|
||||||
|
|
||||||
var recipes = OrderRecipes(_setupService.Recipes());
|
var recipes = _setupService.Recipes().ToList();
|
||||||
|
|
||||||
// if no builtin provider, a connection string is mandatory
|
// If no builtin provider, a connection string is mandatory.
|
||||||
if (model.DatabaseProvider != SetupDatabaseType.Builtin && string.IsNullOrEmpty(model.DatabaseConnectionString))
|
if (model.DatabaseProvider != SetupDatabaseType.Builtin && string.IsNullOrEmpty(model.DatabaseConnectionString))
|
||||||
ModelState.AddModelError("DatabaseConnectionString", T("A connection string is required").Text);
|
ModelState.AddModelError("DatabaseConnectionString", T("A connection string is required.").Text);
|
||||||
|
|
||||||
if (!String.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) {
|
if (!string.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) {
|
||||||
ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match").Text);
|
ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match.").Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.DatabaseProvider != SetupDatabaseType.Builtin && !String.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) {
|
if (model.DatabaseProvider != SetupDatabaseType.Builtin && !string.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) {
|
||||||
model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim();
|
model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim();
|
||||||
if(!Char.IsLetter(model.DatabaseTablePrefix[0])) {
|
if(!char.IsLetter(model.DatabaseTablePrefix[0])) {
|
||||||
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must begin with a letter").Text);
|
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must begin with a letter.").Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) {
|
if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) {
|
||||||
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must contain letters or digits").Text);
|
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must contain letters or digits.").Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (model.Recipe == null) {
|
if (model.Recipe == null) {
|
||||||
if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
|
if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
|
||||||
ModelState.AddModelError("Recipe", T("No recipes were found in the Setup module").Text);
|
ModelState.AddModelError("Recipe", T("No recipes were found.").Text);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
model.Recipe = DefaultRecipe;
|
model.Recipe = DefaultRecipe;
|
||||||
@@ -155,7 +151,7 @@ namespace Orchard.Setup.Controllers {
|
|||||||
// uses a "single lock" mechanism for compiling views).
|
// uses a "single lock" mechanism for compiling views).
|
||||||
_viewsBackgroundCompilation.Stop();
|
_viewsBackgroundCompilation.Stop();
|
||||||
|
|
||||||
// redirect to the welcome page.
|
// Redirect to the welcome page.
|
||||||
return Redirect("~/" + _shellSettings.RequestUrlPrefix);
|
return Redirect("~/" + _shellSettings.RequestUrlPrefix);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.Error(ex, "Setup failed");
|
Logger.Error(ex, "Setup failed");
|
||||||
@@ -170,19 +166,5 @@ namespace Orchard.Setup.Controllers {
|
|||||||
return IndexViewResult(model);
|
return IndexViewResult(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Recipe> OrderRecipes(IEnumerable<Recipe> recipes) {
|
|
||||||
var recipeList = new List<Recipe>();
|
|
||||||
var tempList = new List<Recipe>();
|
|
||||||
foreach (var recipe in recipes) {
|
|
||||||
if (recipe.Name == DefaultRecipe) {
|
|
||||||
recipeList.Add(recipe);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tempList.Add(recipe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return recipeList.Concat(tempList).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<Description>A recipe providing the features you need for a personal blog site.</Description>
|
<Description>A recipe providing the features you need for a personal blog site.</Description>
|
||||||
<Author>The Orchard Team</Author>
|
<Author>The Orchard Team</Author>
|
||||||
<WebSite>http://orchardproject.net</WebSite>
|
<WebSite>http://orchardproject.net</WebSite>
|
||||||
|
<Category>Default</Category>
|
||||||
<Tags>blog</Tags>
|
<Tags>blog</Tags>
|
||||||
<Version>1.0</Version>
|
<Version>1.0</Version>
|
||||||
<IsSetupRecipe>true</IsSetupRecipe>
|
<IsSetupRecipe>true</IsSetupRecipe>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<Description>A recipe providing only the core Orchard framework, with limited end-user functionality. This is useful for development scenarios.</Description>
|
<Description>A recipe providing only the core Orchard framework, with limited end-user functionality. This is useful for development scenarios.</Description>
|
||||||
<Author>The Orchard Team</Author>
|
<Author>The Orchard Team</Author>
|
||||||
<WebSite>http://orchardproject.net</WebSite>
|
<WebSite>http://orchardproject.net</WebSite>
|
||||||
|
<Category>Default</Category>
|
||||||
<Tags>developer</Tags>
|
<Tags>developer</Tags>
|
||||||
<Version>1.0</Version>
|
<Version>1.0</Version>
|
||||||
<IsSetupRecipe>true</IsSetupRecipe>
|
<IsSetupRecipe>true</IsSetupRecipe>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<Description>The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets and basic navigation.</Description>
|
<Description>The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets and basic navigation.</Description>
|
||||||
<Author>The Orchard Team</Author>
|
<Author>The Orchard Team</Author>
|
||||||
<WebSite>http://orchardproject.net</WebSite>
|
<WebSite>http://orchardproject.net</WebSite>
|
||||||
|
<Category>Default</Category>
|
||||||
<Tags></Tags>
|
<Tags></Tags>
|
||||||
<Version>1.0</Version>
|
<Version>1.0</Version>
|
||||||
<IsSetupRecipe>true</IsSetupRecipe>
|
<IsSetupRecipe>true</IsSetupRecipe>
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
Script.Require("ShapesBase");
|
Script.Require("ShapesBase");
|
||||||
Script.Include("setup.js");
|
Script.Include("setup.js");
|
||||||
}
|
}
|
||||||
|
@{
|
||||||
|
var groupedRecipes = Model.Recipes.Where(x => !String.IsNullOrWhiteSpace(x.Category)).GroupBy(x => x.Category);
|
||||||
|
var unspecifiedCategoryRecipes = Model.Recipes.Where(x => String.IsNullOrWhiteSpace(x.Category)).ToList();
|
||||||
|
}
|
||||||
<h1>@Html.TitleForPage(T("Get Started").ToString())</h1>
|
<h1>@Html.TitleForPage(T("Get Started").ToString())</h1>
|
||||||
|
|
||||||
@using (Html.BeginFormAntiForgeryPost()) {
|
@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
@@ -75,8 +79,21 @@ if (!Model.DatabaseIsPreconfigured) {
|
|||||||
<div>@T("Orchard Recipes allow you to setup your site with additional pre-configured options, features and settings out of the box.")</div>
|
<div>@T("Orchard Recipes allow you to setup your site with additional pre-configured options, features and settings out of the box.")</div>
|
||||||
<div>
|
<div>
|
||||||
<select id="@Html.FieldIdFor(m => m.Recipe)" name="@Html.FieldNameFor(m => m.Recipe)" class="recipe">
|
<select id="@Html.FieldIdFor(m => m.Recipe)" name="@Html.FieldNameFor(m => m.Recipe)" class="recipe">
|
||||||
@foreach(var recipe in Model.Recipes) {
|
@foreach(var recipeGroup in groupedRecipes.OrderBy(x => x.Key)) {
|
||||||
@Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description })
|
if (groupedRecipes.Count() > 1) {
|
||||||
|
<optgroup label="@recipeGroup.Key"></optgroup>
|
||||||
|
}
|
||||||
|
foreach (var recipe in recipeGroup.OrderBy(x => x.Name)) {
|
||||||
|
@Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (unspecifiedCategoryRecipes.Any()) {
|
||||||
|
if (groupedRecipes.Any()) {
|
||||||
|
<optgroup label="@T("Unspecified")"></optgroup>
|
||||||
|
}
|
||||||
|
foreach (var recipe in unspecifiedCategoryRecipes.OrderBy(x => x.Name)) {
|
||||||
|
@Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace Orchard.Recipes.Models {
|
|||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
public bool IsSetupRecipe { get; set; }
|
public bool IsSetupRecipe { get; set; }
|
||||||
public DateTime? ExportUtc { get; set; }
|
public DateTime? ExportUtc { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
public string Tags { get; set; }
|
public string Tags { get; set; }
|
||||||
public IEnumerable<RecipeStep> RecipeSteps { get; set; }
|
public IEnumerable<RecipeStep> RecipeSteps { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user