Merge remote-tracking branch 'origin/1.10.x' into dev

This commit is contained in:
Daniel Stolt
2016-12-06 16:00:41 +01:00
25 changed files with 389 additions and 115 deletions

View File

@@ -205,7 +205,8 @@ namespace Orchard.Tests.Modules.Users.Controllers {
@"Ima.Fool@example.com",
@"""Ima.Fool""@example.com",
@"""Ima Fool""@example.com",
"2xxx1414@i.ua"
"2xxx1414@i.ua",
"Dreißig-öffentliche-Ämter-in-Übersee@Beispiel.de"
)]
string email)
{

View File

@@ -1,10 +1,20 @@
using Orchard.ContentManagement.MetaData;
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Autoroute.Models;
using Orchard.Autoroute.Settings;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
using Orchard.Localization.Services;
namespace Orchard.Autoroute
{
public class Migrations : DataMigrationImpl {
namespace Orchard.Autoroute {
public class Migrations : DataMigrationImpl {
private readonly ICultureManager _cultureManager;
public Migrations(ICultureManager cultureManager) {
_cultureManager = cultureManager;
}
public int Create() {
SchemaBuilder.CreateTable("AutoroutePartRecord",
@@ -49,5 +59,46 @@ namespace Orchard.Autoroute
return 4;
}
public int UpdateFrom4() {
// Adding some culture neutral patterns if they don't exist
var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions()
.Where(t => t.Parts.Any(p => p.PartDefinition.Name.Equals(typeof(AutoroutePart).Name)))
.Select(s => new { contentTypeName = s.Name, autoroutePart = s.Parts.First(x => x.PartDefinition.Name == "AutoroutePart") });
foreach (var partDefinition in autoroutePartDefinitions) {
var settingsDictionary = partDefinition.autoroutePart.Settings;
var settings = settingsDictionary.GetModel<AutorouteSettings>();
if (!settings.Patterns.Any(x => String.IsNullOrWhiteSpace(x.Culture))) {
string siteCulture = _cultureManager.GetSiteCulture();
List<string> newPatterns = new List<string>();
if (settings.Patterns.Any(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase))) {
var siteCulturePatterns = settings.Patterns.Where(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList();
foreach (RoutePattern pattern in siteCulturePatterns) {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", pattern.Name, pattern.Pattern, pattern.Description));
}
}
else {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", "Title", "{Content.Slug}", "my-title"));
}
if (settingsDictionary.ContainsKey("AutorouteSettings.PatternDefinitions")) {
string oldPatterns = settingsDictionary["AutorouteSettings.PatternDefinitions"];
if (oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]"))
newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2));
}
ContentDefinitionManager.AlterTypeDefinition(partDefinition.contentTypeName, cfg => cfg
.WithPart("AutoroutePart", builder => builder
.WithSetting("AutorouteSettings.PatternDefinitions", "[" + String.Join(",", newPatterns) + "]")
));
}
}
return 5;
}
}
}

View File

@@ -50,19 +50,24 @@ namespace Orchard.Autoroute.Providers.ContentDefinition {
public void ContentPartAttached(ContentPartAttachedContext context) {
if (context.ContentPartName == "AutoroutePart") {
//Create pattern and default pattern for each culture installed
// Create pattern and default pattern for each culture installed and for the neutral culture
//get cultures
// Get cultures
var SiteCultures = _cultureManager.ListCultures().ToList();
//Create Patterns and DefaultPatterns
// Adding a null culture for the culture neutral pattern
List<string> cultures = new List<string>();
cultures.Add(null);
cultures.AddRange(SiteCultures);
// Create Patterns and DefaultPatterns
var settings = new AutorouteSettings {
Patterns = new List<RoutePattern>()
};
List<RoutePattern> newPatterns = new List<RoutePattern>();
List<DefaultPattern> newDefaultPatterns = new List<DefaultPattern>();
foreach (string culture in SiteCultures) {
foreach (string culture in cultures) {
newPatterns.Add(new RoutePattern {
Name = "Title",
Description = "my-title",

View File

@@ -135,35 +135,47 @@ namespace Orchard.Autoroute.Services {
public RoutePattern GetDefaultPattern(string contentType, string culture) {
var settings = GetTypePartSettings(contentType).GetModel<AutorouteSettings>();
var defaultPattern = settings.DefaultPatterns.FirstOrDefault(x => x.Culture == culture);
var defaultPatternIndex = defaultPattern != null ? defaultPattern.PatternIndex : "0";
if (String.IsNullOrWhiteSpace(defaultPatternIndex))
defaultPatternIndex = "0";
if (settings.UseCulturePattern) {
var defaultPatternIndex = "0";
if (!settings.DefaultPatterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
var patternIndex = String.IsNullOrWhiteSpace(settings.DefaultPatternIndex) ? "0" : settings.DefaultPatternIndex;
// Lazy updating from old setting.
if (String.Equals(culture, _cultureManager.GetSiteCulture(), StringComparison.OrdinalIgnoreCase)) {
settings.DefaultPatterns.Add(new DefaultPattern { PatternIndex = patternIndex, Culture = culture });
return settings.Patterns.Where(x => x.Culture == null).ElementAt(Convert.ToInt32(defaultPatternIndex));
if (!settings.DefaultPatterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
// If no default pattern exists for the language return the default culture neutral pattern if it exists, else a generic pattern
if (settings.Patterns.Any(x => String.IsNullOrEmpty(x.Culture))) {
defaultPatternIndex = GetDefaultPatternIndex(contentType, null);
return settings.Patterns.Where(x => String.IsNullOrEmpty(x.Culture)).ElementAt(Convert.ToInt32(defaultPatternIndex));
}
else {
return new RoutePattern { Name = "Title", Description = "my-title", Pattern = "{Content.Slug}", Culture = culture };
}
}
else {
settings.DefaultPatterns.Add(new DefaultPattern { PatternIndex = "0", Culture = culture });
return new RoutePattern { Name = "Title", Description = "my-title", Pattern = "{Content.Slug}", Culture = culture };
// If patterns for the specified culture exist search one of them, else search a culture neutral pattern
var patternCultureSearch = settings.Patterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase)) ? culture : null;
defaultPatternIndex = GetDefaultPatternIndex(contentType, patternCultureSearch);
if (settings.Patterns.Any()) {
if (settings.Patterns.Where(x => x.Culture == patternCultureSearch).ElementAt(Convert.ToInt32(defaultPatternIndex)) != null) {
return settings.Patterns.Where(x => x.Culture == patternCultureSearch).ElementAt(Convert.ToInt32(defaultPatternIndex));
}
}
}
else {
// Using the culture neutral pattern
if (settings.Patterns.Any(x => String.IsNullOrEmpty(x.Culture))) {
var defaultPatternIndex = GetDefaultPatternIndex(contentType, null);
// If no default culture neutral pattern exist use the default pattern
if (!settings.DefaultPatterns.Any(x => String.IsNullOrEmpty(x.Culture))) {
var patternIndex = String.IsNullOrWhiteSpace(settings.DefaultPatternIndex) ? "0" : settings.DefaultPatternIndex;
settings.DefaultPatterns.Add(new DefaultPattern { PatternIndex = patternIndex, Culture = null });
}
return settings.Patterns.Where(x => String.IsNullOrEmpty(x.Culture)).ElementAt(Convert.ToInt32(defaultPatternIndex));
}
}
// Return a default pattern if set.
var patternCultureSearch = settings.Patterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase)) ? culture : null;
if (settings.Patterns.Any()) {
if (settings.Patterns.Where(x => x.Culture == patternCultureSearch).ElementAt(Convert.ToInt32(defaultPatternIndex)) != null) {
return settings.Patterns.Where(x => x.Culture == patternCultureSearch).ElementAt(Convert.ToInt32(defaultPatternIndex));
};
}
// Return a default pattern if none is defined.
// Return a default pattern if none is defined
return new RoutePattern { Name = "Title", Description = "my-title", Pattern = "{Content.Slug}", Culture = culture };
}
@@ -222,6 +234,23 @@ namespace Orchard.Autoroute.Services {
return contentDefinition.Parts.First(x => x.PartDefinition.Name == "AutoroutePart").Settings;
}
private string GetDefaultPatternIndex(string contentType, string culture) {
var settings = GetTypePartSettings(contentType).GetModel<AutorouteSettings>();
DefaultPattern defaultPattern = null;
if (String.IsNullOrEmpty(culture))
defaultPattern = settings.DefaultPatterns.FirstOrDefault(x => String.IsNullOrEmpty(x.Culture));
else
defaultPattern = settings.DefaultPatterns.FirstOrDefault(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase));
var defaultPatternIndex = defaultPattern != null ? defaultPattern.PatternIndex : "0";
if (String.IsNullOrWhiteSpace(defaultPatternIndex))
defaultPatternIndex = "0";
return defaultPatternIndex;
}
private static int? GetSlugVersion(string path, string potentialConflictingPath) {
int v;
var slugParts = potentialConflictingPath.Split(new[] { path }, StringSplitOptions.RemoveEmptyEntries);

View File

@@ -28,56 +28,55 @@ namespace Orchard.Autoroute.Settings {
var settings = definition.Settings.GetModel<AutorouteSettings>();
//get cultures
// Get cultures
settings.SiteCultures = _cultureManager.ListCultures().ToList();
//get default site culture
// Get default site culture
settings.DefaultSiteCulture = _cultureManager.GetSiteCulture();
//if a culture is not set on the pattern we set it to the default site culture for backward compatibility
if (!settings.Patterns.Any(x => String.Equals(x.Culture, settings.DefaultSiteCulture, StringComparison.OrdinalIgnoreCase))) {
foreach (RoutePattern pattern in settings.Patterns.Where(x => String.IsNullOrWhiteSpace(x.Culture))) {
settings.Patterns.Where(x => x.GetHashCode() == pattern.GetHashCode()).FirstOrDefault().Culture = settings.DefaultSiteCulture;
}
}
//Adding Patterns for the UI
// Adding Patterns for the UI
List<RoutePattern> newPatterns = new List<RoutePattern>();
// Adding a null culture for the culture neutral pattern
List<string> cultures = new List<string>();
cultures.Add(null);
cultures.AddRange(settings.SiteCultures);
int current = 0;
foreach (string culture in settings.SiteCultures) {
foreach (string culture in cultures) {
// Adding all existing patterns for the culture
foreach (RoutePattern routePattern in settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
if (settings.Patterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
newPatterns.Add(settings.Patterns[current]);
} else {
newPatterns.Add(new RoutePattern {
Name = "Title",
Description = "my-title",
Pattern = "{Content.Slug}",
Culture = settings.DefaultSiteCulture
});
}
newPatterns.Add(settings.Patterns[current]);
current++;
}
//We add a pattern for each culture if there is none
// Adding a pattern for each culture if there is none
if (!settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase)).Any()) {
newPatterns.Add(new RoutePattern { Culture = culture, Name = "Title", Description = "my-title", Pattern = "{Content.Slug}" });
}
//we add a new empty line for each culture
// Adding a new empty line for each culture
newPatterns.Add(new RoutePattern { Culture = culture, Name = null, Description = null, Pattern = null });
// if the content type has no defaultPattern for autoroute, then assign one
if (!settings.DefaultPatterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
//if we are in the default culture check the old setting
// If the content type has no defaultPattern for autoroute, assign one
bool defaultPatternExists = false;
if (String.IsNullOrEmpty(culture))
defaultPatternExists = settings.DefaultPatterns.Any(x => String.IsNullOrEmpty(x.Culture));
else
defaultPatternExists = settings.DefaultPatterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase));
if (!defaultPatternExists) {
// If in the default culture check the old setting
if (String.Equals(culture, _cultureManager.GetSiteCulture(), StringComparison.OrdinalIgnoreCase)) {
var defaultPatternIndex = settings.DefaultPatternIndex;
if (!String.IsNullOrWhiteSpace(defaultPatternIndex)) {
var patternIndex = defaultPatternIndex;
settings.DefaultPatterns.Add(new DefaultPattern { Culture = settings.DefaultSiteCulture, PatternIndex = patternIndex });
} else {
}
else {
settings.DefaultPatterns.Add(new DefaultPattern { PatternIndex = "0", Culture = culture });
}
} else {
}
else {
settings.DefaultPatterns.Add(new DefaultPattern { PatternIndex = "0", Culture = culture });
}
}
@@ -96,25 +95,51 @@ namespace Orchard.Autoroute.Settings {
Patterns = new List<RoutePattern>()
};
//get cultures
// Get cultures
settings.SiteCultures = _cultureManager.ListCultures().ToList();
if (updateModel.TryUpdateModel(settings, "AutorouteSettings", null, null)) {
//TODO need to add validations client and/or server side here
// remove empty patterns
// If some default pattern is an empty pattern set it to the first pattern for the language
List<DefaultPattern> newDefaultPatterns = new List<DefaultPattern>();
foreach (var defaultPattern in settings.DefaultPatterns) {
RoutePattern correspondingPattern = null;
if (string.IsNullOrEmpty(defaultPattern.Culture))
correspondingPattern = settings.Patterns.Where(x => String.IsNullOrEmpty(x.Culture)).ElementAt(Convert.ToInt32(defaultPattern.PatternIndex));
else
correspondingPattern = settings.Patterns.Where(x => String.Equals(x.Culture, defaultPattern.Culture, StringComparison.OrdinalIgnoreCase)).ElementAt(Convert.ToInt32(defaultPattern.PatternIndex));
if (String.IsNullOrWhiteSpace(correspondingPattern.Name) && String.IsNullOrWhiteSpace(correspondingPattern.Pattern) && String.IsNullOrWhiteSpace(correspondingPattern.Description))
newDefaultPatterns.Add(new DefaultPattern { Culture = defaultPattern.Culture, PatternIndex = "0" });
else
newDefaultPatterns.Add(defaultPattern);
}
settings.DefaultPatterns = newDefaultPatterns;
// Remove empty patterns
var patterns = settings.Patterns;
patterns.RemoveAll(p => String.IsNullOrWhiteSpace(p.Name) && String.IsNullOrWhiteSpace(p.Pattern) && String.IsNullOrWhiteSpace(p.Description));
//If there is no default pattern for each culture we set default ones
// Adding a null culture for the culture neutral pattern
List<string> cultures = new List<string>();
cultures.Add(null);
cultures.AddRange(settings.SiteCultures);
//If there is no pattern for some culture create a default one
List<RoutePattern> newPatterns = new List<RoutePattern>();
int current = 0;
foreach (string culture in settings.SiteCultures) {
foreach (string culture in cultures) {
if (settings.Patterns.Any(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
foreach (RoutePattern routePattern in settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) {
newPatterns.Add(settings.Patterns[current]);
current++;
}
} else {
}
else {
newPatterns.Add(new RoutePattern {
Name = "Title",
Description = "my-title",
@@ -128,7 +153,7 @@ namespace Orchard.Autoroute.Settings {
settings.Patterns = newPatterns;
// update the settings builder
// Update the settings builder
settings.Build(builder);
}

View File

@@ -1,11 +1,15 @@
@model Orchard.Autoroute.Settings.AutorouteSettings
@using Orchard.Utility.Extensions;
@{
Script.Require("AutorouteBrowser");
Style.Require("AutorouteSettings");
int patternCount = 0;
int patternCultureCount = 0;
List<string> cultures = new List<string>();
cultures.Add(null);
cultures.AddRange(Model.SiteCultures);
}
<fieldset>
<div>
@@ -40,10 +44,10 @@
int i = 1;
string cssClass = "";
}
<li class="first selected"><a class="culture" href="#cat-@Model.DefaultSiteCulture">@Model.DefaultSiteCulture</a></li>
@foreach (var culture in Model.SiteCultures) {
if (culture != Model.DefaultSiteCulture) {
cssClass = i == Model.SiteCultures.Count - 1 ? "last" : "middle";
<li class="first selected"><a class="culture" href="#cat-culture-neutral">@T("All cultures")</a></li>
@foreach (var culture in cultures) {
if (!String.IsNullOrEmpty(culture)) {
cssClass = i == cultures.Count - 1 ? "last" : "middle";
<li class="@cssClass" style="@(Model.UseCulturePattern == false ? "display:none;" : "")"><a class="culture" href="#cat-@culture">@culture</a></li>
i++;
}
@@ -51,8 +55,8 @@
</ul>
</div>
<div id="content">
@foreach (var culture in Model.SiteCultures) {
<fieldset id="cat-@culture" class="items @(culture == Model.DefaultSiteCulture ? "default" : "")" style="@(culture == Model.DefaultSiteCulture ? "display:block;" : "display:none;")">
@foreach (var culture in cultures) {
<fieldset id="cat-@(String.IsNullOrEmpty(culture) ? "culture-neutral" : culture)" class="items @(String.IsNullOrEmpty(culture) ? "default" : "")" style="@(String.IsNullOrEmpty(culture) ? "display:block;" : "display:none;")">
<table class="autoroute-settings-patterns">
<tr>
<th class="autoroute-settings-default">@T("Default")</th>
@@ -63,7 +67,7 @@
</tr>
@for (int index = 0; index < Model.Patterns.Where(x => x.Culture == culture).Count(); index++) {
<tr>
<td>@Html.RadioButtonFor(m => m.DefaultPatterns[Model.SiteCultures.IndexOf(culture)].Culture, culture + "|" + patternCultureCount, patternCultureCount.ToString() == Model.DefaultPatterns[Model.SiteCultures.IndexOf(culture)].PatternIndex ? new { @checked = "checked" } : null)</td>
<td>@Html.RadioButtonFor(m => m.DefaultPatterns[cultures.IndexOf(culture)].Culture, culture + "|" + patternCultureCount, patternCultureCount.ToString() == Model.DefaultPatterns[cultures.IndexOf(culture)].PatternIndex ? new { @checked = "checked" } : null)</td>
<td>@Html.TextBoxFor(m => m.Patterns[patternCount].Name, new { @class = "text" })</td>
<td>@Html.TextBoxFor(m => m.Patterns[patternCount].Pattern, new { @class = "tokenized text" })</td>
<td>@Html.TextBoxFor(m => m.Patterns[patternCount].Description, new { @class = "text" })</td>

View File

@@ -165,6 +165,13 @@ namespace Orchard.ImportExport.Commands {
}
if (!String.IsNullOrEmpty(customSteps)) {
var customStepsList = customSteps.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var customStepName in customStepsList) {
GetOrCreateElement(stepsElement, customStepName);
}
//Still need CustomStepsStep to support older export steps created by users
var customStepsElement = GetOrCreateElement(stepsElement, "CustomSteps");
customStepsElement.Attr("Steps", customSteps);
}

View File

@@ -14,11 +14,13 @@ using Orchard.Recipes.Services;
namespace Orchard.ImportExport.Providers.ExportActions {
public class BuildRecipeAction : ExportAction {
private readonly IEnumerable<IRecipeBuilderStep> _recipeBuilderSteps;
private readonly IRecipeBuilderStepResolver _recipeBuilderStepResolver;
private readonly IRecipeBuilder _recipeBuilder;
private readonly IOrchardServices _orchardServices;
public BuildRecipeAction(IEnumerable<IRecipeBuilderStep> recipeBuilderSteps, IRecipeBuilder recipeBuilder, IOrchardServices orchardServices) {
public BuildRecipeAction(IRecipeBuilderStepResolver recipeBuilderStepResolver, IEnumerable<IRecipeBuilderStep> recipeBuilderSteps, IRecipeBuilder recipeBuilder, IOrchardServices orchardServices) {
_recipeBuilderSteps = recipeBuilderSteps;
_recipeBuilderStepResolver = recipeBuilderStepResolver;
_recipeBuilder = recipeBuilder;
_orchardServices = orchardServices;
@@ -60,10 +62,7 @@ namespace Orchard.ImportExport.Providers.ExportActions {
}
else {
var exportStepNames = viewModel.Steps.Where(x => x.IsSelected).Select(x => x.Name);
var stepsQuery = from name in exportStepNames
let provider = _recipeBuilderSteps.SingleOrDefault(x => x.Name == name)
where provider != null
select provider;
var stepsQuery = _recipeBuilderStepResolver.Resolve(exportStepNames);
var steps = stepsQuery.ToArray();
var stepUpdater = new Updater(updater, secondHalf => String.Format("{0}.{1}", Prefix, secondHalf));
foreach (var exportStep in steps) {
@@ -86,7 +85,7 @@ namespace Orchard.ImportExport.Providers.ExportActions {
return;
foreach (var stepElement in recipeBuilderStepsElement.Elements()) {
var step = _recipeBuilderSteps.SingleOrDefault(x => x.Name == stepElement.Name.LocalName);
var step = _recipeBuilderStepResolver.Resolve(stepElement.Name.LocalName);
if (step != null) {
var stepContext = new RecipeBuilderStepConfigurationContext(stepElement);

View File

@@ -1,4 +1,5 @@
using Orchard.Environment.Extensions;
using Orchard.Security;
using Orchard.UI.Navigation;
namespace Orchard.JobsQueue {
@@ -11,6 +12,7 @@ namespace Orchard.JobsQueue {
builder
.AddImageSet("jobsqueue")
.Add(T("Jobs Queue"), "15.0", item => {
item.Permission(StandardPermissions.SiteOwner);
item.Action("List", "Admin", new { area = "Orchard.JobsQueue" });
item.LinkToFirstChild(false);
});

View File

@@ -0,0 +1,20 @@
using System;
using Orchard.ContentManagement;
using Orchard.MediaLibrary.Providers;
using Orchard.Security;
namespace Orchard.MediaLibrary.Implementation {
public class DefaultMediaUsername : IMediaFolderProvider {
public virtual string GetFolderName(IUser content) {
string folder = "";
foreach (char c in content.UserName) {
if (char.IsLetterOrDigit(c)) {
folder += c;
}
else
folder += "_" + String.Format("{0:X}", Convert.ToInt32(c));
}
return folder;
}
}
}

View File

@@ -128,6 +128,7 @@
<Compile Include="Extensions\MediaMetaDataExtensions.cs" />
<Compile Include="Factories\VectorImageFactory.cs" />
<Compile Include="Handlers\MediaLibrarySettingsPartHandler.cs" />
<Compile Include="Implementation\DefaultMediaUsername.cs" />
<Compile Include="Models\MediaLibrarySettingsPart.cs" />
<Compile Include="Models\VectorImagePart.cs" />
<Compile Include="Models\IMediaFolder.cs" />
@@ -200,6 +201,7 @@
<Compile Include="ResourceManifest.cs" />
<Compile Include="Security\MediaAuthorizationEventHandler.cs" />
<Compile Include="Services\IMediaLibraryService.cs" />
<Compile Include="Providers\IMediaFolderProvider.cs" />
<Compile Include="Services\MediaLibraryService.cs" />
<Compile Include="Services\Shapes.cs" />
<Compile Include="Services\XmlRpcHandler.cs" />

View File

@@ -0,0 +1,7 @@
using Orchard.Security;
namespace Orchard.MediaLibrary.Providers {
public interface IMediaFolderProvider : IDependency {
string GetFolderName(IUser content);
}
}

View File

@@ -12,6 +12,7 @@ using Orchard.MediaLibrary.Factories;
using Orchard.MediaLibrary.Models;
using Orchard.Core.Title.Models;
using Orchard.Validation;
using Orchard.MediaLibrary.Providers;
namespace Orchard.MediaLibrary.Services {
public class MediaLibraryService : IMediaLibraryService {
@@ -19,18 +20,20 @@ namespace Orchard.MediaLibrary.Services {
private readonly IMimeTypeProvider _mimeTypeProvider;
private readonly IStorageProvider _storageProvider;
private readonly IEnumerable<IMediaFactorySelector> _mediaFactorySelectors;
private readonly IMediaFolderProvider _mediaFolderProvider;
private static char[] HttpUnallowed = new char[] { '<', '>', '*', '%', '&', ':', '\\', '?', '#' };
public MediaLibraryService(
IOrchardServices orchardServices,
IMimeTypeProvider mimeTypeProvider,
IStorageProvider storageProvider,
IEnumerable<IMediaFactorySelector> mediaFactorySelectors) {
IEnumerable<IMediaFactorySelector> mediaFactorySelectors,
IMediaFolderProvider mediaFolderProvider) {
_orchardServices = orchardServices;
_mimeTypeProvider = mimeTypeProvider;
_storageProvider = storageProvider;
_mediaFactorySelectors = mediaFactorySelectors;
_mediaFolderProvider = mediaFolderProvider;
T = NullLocalizer.Instance;
}
@@ -229,8 +232,7 @@ namespace Orchard.MediaLibrary.Services {
if (_orchardServices.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
var currentUser = _orchardServices.WorkContext.CurrentUser;
var userPath = _storageProvider.Combine("Users", currentUser.UserName);
var userPath = _storageProvider.Combine("Users", _mediaFolderProvider.GetFolderName(currentUser));
return new MediaFolder() {
Name = currentUser.UserName,
MediaPath = userPath

View File

@@ -24,7 +24,7 @@ using Orchard.Utility.Extensions;
namespace Orchard.Projections.Drivers {
public class ProjectionPartDriver : ContentPartDriver<ProjectionPart> {
private readonly IRepository<QueryPartRecord> _queryRepository;
private readonly IProjectionManager _projectionManager;
private readonly IProjectionManagerExtension _projectionManager;
private readonly IFeedManager _feedManager;
private readonly ITokenizer _tokenizer;
private readonly IDisplayHelperFactory _displayHelperFactory;
@@ -34,7 +34,7 @@ namespace Orchard.Projections.Drivers {
public ProjectionPartDriver(
IOrchardServices services,
IRepository<QueryPartRecord> queryRepository,
IProjectionManager projectionManager,
IProjectionManagerExtension projectionManager,
IFeedManager feedManager,
ITokenizer tokenizer,
IDisplayHelperFactory displayHelperFactory,
@@ -110,7 +110,7 @@ namespace Orchard.Projections.Drivers {
_feedManager.Register(metaData.DisplayText, "rss", new RouteValueDictionary { { "projection", part.Id } });
// execute the query
var contentItems = _projectionManager.GetContentItems(query.Id, pager.GetStartIndex() + part.Record.Skip, pager.PageSize).ToList();
var contentItems = _projectionManager.GetContentItems(query.Id, part, pager.GetStartIndex() + part.Record.Skip, pager.PageSize).ToList();
// sanity check so that content items with ProjectionPart can't be added here, or it will result in an infinite loop
contentItems = contentItems.Where(x => !x.Has<ProjectionPart>()).ToList();
@@ -122,7 +122,7 @@ namespace Orchard.Projections.Drivers {
// create pager shape
if (part.Record.DisplayPager) {
var contentItemsCount = _projectionManager.GetCount(query.Id) - part.Record.Skip;
var contentItemsCount = _projectionManager.GetCount(query.Id, part) - part.Record.Skip;
contentItemsCount = Math.Max(0, contentItemsCount);
pagerShape.TotalItemCount(contentItemsCount);
}

View File

@@ -175,6 +175,7 @@
<Compile Include="Providers\Layouts\ShapeLayoutForms.cs" />
<Compile Include="Providers\Properties\CustomValueProperties.cs" />
<Compile Include="Navigation\NavigationQueryProvider.cs" />
<Compile Include="Services\IProjectionManagerExtension.cs" />
<Compile Include="Shapes.cs" />
<Compile Include="Descriptors\Layout\LayoutComponentResult.cs" />
<Compile Include="Descriptors\Layout\LayoutContext.cs" />

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.Projections.Descriptors;
using Orchard.Projections.Descriptors.Property;
using Orchard.Projections.Descriptors.Filter;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Descriptors.SortCriterion;
namespace Orchard.Projections.Services {
public interface IProjectionManagerExtension : IProjectionManager {
IEnumerable<ContentItem> GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0);
int GetCount(int queryId, ContentPart part);
}
}

View File

@@ -14,7 +14,7 @@ using Orchard.Projections.Models;
using Orchard.Tokens;
namespace Orchard.Projections.Services {
public class ProjectionManager : IProjectionManager{
public class ProjectionManager : IProjectionManagerExtension {
private readonly ITokenizer _tokenizer;
private readonly IEnumerable<IFilterProvider> _filterProviders;
private readonly IEnumerable<ISortCriterionProvider> _sortCriterionProviders;
@@ -104,6 +104,33 @@ namespace Orchard.Projections.Services {
}
public int GetCount(int queryId) {
return GetCount(queryId, null);
}
public int GetCount(int queryId, ContentPart part) {
var queryRecord = _queryRepository.Get(queryId);
if (queryRecord == null) {
throw new ArgumentException("queryId");
}
// prepares tokens
Dictionary<string, object> tokens = new Dictionary<string, object>();
if (part != null) {
tokens.Add("Content", part.ContentItem);
}
// aggregate the result for each group query
return GetContentQueries(queryRecord, Enumerable.Empty<SortCriterionRecord>(), tokens)
.Sum(contentQuery => contentQuery.Count());
}
public IEnumerable<ContentItem> GetContentItems(int queryId, int skip = 0, int count = 0) {
return GetContentItems(queryId, null, skip, count);
}
public IEnumerable<ContentItem> GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0) {
var availableSortCriteria = DescribeSortCriteria().ToList();
var queryRecord = _queryRepository.Get(queryId);
@@ -111,36 +138,27 @@ namespace Orchard.Projections.Services {
throw new ArgumentException("queryId");
}
// aggregate the result for each group query
return GetContentQueries(queryRecord, Enumerable.Empty<SortCriterionRecord>())
.Sum(contentQuery => contentQuery.Count());
}
public IEnumerable<ContentItem> GetContentItems(int queryId, int skip = 0, int count = 0) {
var availableSortCriteria = DescribeSortCriteria().ToList();
var queryRecord = _queryRepository.Get(queryId);
if(queryRecord == null) {
throw new ArgumentException("queryId");
}
var contentItems = new List<ContentItem>();
// prepares tokens
Dictionary<string, object> tokens = new Dictionary<string, object>();
if (part != null) {
tokens.Add("Content", part.ContentItem);
}
// aggregate the result for each group query
foreach(var contentQuery in GetContentQueries(queryRecord, queryRecord.SortCriteria.OrderBy(sc => sc.Position))) {
foreach (var contentQuery in GetContentQueries(queryRecord, queryRecord.SortCriteria.OrderBy(sc => sc.Position), tokens)) {
contentItems.AddRange(contentQuery.Slice(skip, count));
}
if(queryRecord.FilterGroups.Count <= 1) {
if (queryRecord.FilterGroups.Count <= 1) {
return contentItems;
}
// re-executing the sorting with the cumulated groups
var ids = contentItems.Select(c => c.Id).ToArray();
if(ids.Length == 0) {
if (ids.Length == 0) {
return Enumerable.Empty<ContentItem>();
}
@@ -173,9 +191,13 @@ namespace Orchard.Projections.Services {
return groupQuery.Slice(skip, count);
}
public IEnumerable<IHqlQuery> GetContentQueries(QueryPartRecord queryRecord, IEnumerable<SortCriterionRecord> sortCriteria) {
public IEnumerable<IHqlQuery> GetContentQueries(QueryPartRecord queryRecord, IEnumerable<SortCriterionRecord> sortCriteria, Dictionary<string, object> tokens) {
var availableFilters = DescribeFilters().ToList();
var availableSortCriteria = DescribeSortCriteria().ToList();
if (tokens == null) {
tokens = new Dictionary<string, object>();
}
// pre-executing all groups
foreach (var group in queryRecord.FilterGroups) {
@@ -184,7 +206,7 @@ namespace Orchard.Projections.Services {
// iterate over each filter to apply the alterations to the query object
foreach (var filter in group.Filters) {
var tokenizedState = _tokenizer.Replace(filter.State, new Dictionary<string, object>());
var tokenizedState = _tokenizer.Replace(filter.State, tokens);
var filterContext = new FilterContext {
Query = contentQuery,
State = FormParametersHelper.ToDynamic(tokenizedState)
@@ -237,7 +259,7 @@ namespace Orchard.Projections.Services {
yield return contentQuery;
}
}
}
}
}

View File

@@ -9,13 +9,13 @@ namespace Orchard.Recipes.Providers.RecipeHandlers {
/// Delegates execution of the step to the appropriate recipe execution step implementation.
/// </summary>
public class RecipeExecutionStepHandler : Component, IRecipeHandler {
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
public RecipeExecutionStepHandler(IEnumerable<IRecipeExecutionStep> recipeExecutionSteps) {
_recipeExecutionSteps = recipeExecutionSteps;
private readonly IRecipeExecutionStepResolver _recipeExecutionStepResolver;
public RecipeExecutionStepHandler(IRecipeExecutionStepResolver recipeExecutionStepResolver) {
_recipeExecutionStepResolver = recipeExecutionStepResolver;
}
public void ExecuteRecipeStep(RecipeContext recipeContext) {
var executionStep = _recipeExecutionSteps.FirstOrDefault(x => x.Names.Contains(recipeContext.RecipeStep.Name));
var executionStep = _recipeExecutionStepResolver.Resolve(recipeContext.RecipeStep.Name);
var recipeExecutionContext = new RecipeExecutionContext {ExecutionId = recipeContext.ExecutionId, RecipeStep = recipeContext.RecipeStep};
if (executionStep != null) {

View File

@@ -52,6 +52,7 @@ namespace Orchard.Scripting.CSharp.Services {
Engine.Run("using System;");
Engine.Run("using System.Collections.Generic;");
Engine.Run("using System.Linq;");
Engine.Run("var dictionary = new Dictionary<string, dynamic>();");
Dictionary = Engine.Evaluate("dictionary") as IDictionary<string, dynamic>;
}

View File

@@ -6,7 +6,7 @@ using System.Web.Security;
namespace Orchard.Users.Models {
public sealed class UserPart : ContentPart<UserPartRecord>, IUser {
public const string EmailPattern =
@"^(?![\.@])(""([^""\r\\]|\\[""\r\\])*""|([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
@"^(?![\.@])(""([^""\r\\]|\\[""\r\\])*""|([-\p{L}0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
+ @"@([a-z0-9][\w-]*\.)+[a-z]{2,}$";
public const int MaxUserNameLength = 255;

View File

@@ -190,12 +190,16 @@
<Compile Include="Recipes\Models\BuildContext.cs" />
<Compile Include="Recipes\Services\IRecipeBuilder.cs" />
<Compile Include="Recipes\Services\IRecipeBuilderStep.cs" />
<Compile Include="Recipes\Services\IRecipeBuilderStepResolver.cs" />
<Compile Include="Recipes\Services\IRecipeExecutionStep.cs" />
<Compile Include="Recipes\Services\IRecipeExecutionStepResolver.cs" />
<Compile Include="Recipes\Services\IRecipeExecutor.cs" />
<Compile Include="Recipes\Services\IRecipeResultAccessor.cs" />
<Compile Include="Recipes\Services\RecipeBuilder.cs" />
<Compile Include="Recipes\Services\RecipeBuilderStep.cs" />
<Compile Include="Recipes\Models\RecipeExecutionContext.cs" />
<Compile Include="Recipes\Services\RecipeExecutionStepResolver.cs" />
<Compile Include="Recipes\Services\RecipeBuilderStepResolver.cs" />
<Compile Include="Recipes\Services\RecipeExecutionLogger.cs" />
<Compile Include="Recipes\Services\RecipeExecutionStep.cs" />
<Compile Include="Recipes\Services\RecipeExecutor.cs" />

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Orchard.Recipes.Services
{
public interface IRecipeBuilderStepResolver : IDependency
{
IRecipeBuilderStep Resolve(string exportStepName);
IEnumerable<IRecipeBuilderStep> Resolve(IEnumerable<string> exportStepNames);
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Orchard.Recipes.Services
{
public interface IRecipeExecutionStepResolver :IDependency
{
IRecipeExecutionStep Resolve(string importStepName);
IEnumerable<IRecipeExecutionStep> Resolve(IEnumerable<string> exportStepNames);
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orchard.Recipes.Services
{
public class RecipeBuilderStepResolver : IRecipeBuilderStepResolver
{
private readonly IEnumerable<IRecipeBuilderStep> _recipeBuilderSteps;
public RecipeBuilderStepResolver(IEnumerable<IRecipeBuilderStep> recipeBuilderSteps) {
_recipeBuilderSteps = recipeBuilderSteps;
}
public IRecipeBuilderStep Resolve(string exportStepName) {
return _recipeBuilderSteps.SingleOrDefault(x => x.Name == exportStepName);
}
public IEnumerable<IRecipeBuilderStep> Resolve(IEnumerable<string> exportStepNames) {
return from name in exportStepNames
let provider = _recipeBuilderSteps.SingleOrDefault(x => x.Name == name)
where provider != null
select provider;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orchard.Recipes.Services
{
public class RecipeExecutionStepResolver : IRecipeExecutionStepResolver
{
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
public RecipeExecutionStepResolver(IEnumerable<IRecipeExecutionStep> recipeExecutionSteps) {
_recipeExecutionSteps = recipeExecutionSteps;
}
public IRecipeExecutionStep Resolve(string importStepName) {
return _recipeExecutionSteps.SingleOrDefault(x => x.Names.Contains(importStepName));
}
public IEnumerable<IRecipeExecutionStep> Resolve(IEnumerable<string> importStepNames) {
return from name in importStepNames
let provider = _recipeExecutionSteps.SingleOrDefault(x => x.Names.Contains(name))
where provider != null
select provider;
}
}
}