Merge branch '1.8.x' into 1.x

Conflicts:
	src/Orchard.Web/Modules/Orchard.Alias/Implementation/Updater/AliasHolderUpdater.cs
	src/Orchard.Web/Modules/Orchard.Alias/Orchard.Alias.csproj
	src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs
This commit is contained in:
Sebastien Ros
2014-09-18 10:53:40 -07:00
45 changed files with 584 additions and 284 deletions

View File

@@ -2,6 +2,7 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.Utilities;
using Orchard.Core.Common.ViewModels;
using Orchard.Localization;
using Orchard.Localization.Services;
@@ -51,7 +52,11 @@ namespace Orchard.Core.Common.DateEditor {
var itemHasNeverBeenPublished = part.PublishedUtc == null;
var thisIsTheInitialVersionRecord = part.ContentItem.Version < 2;
var theDatesHaveNotBeenModified = part.CreatedUtc == part.VersionCreatedUtc;
// Dates are assumed the same if the millisecond part is the only difference.
// This is because SqlCe doesn't support high precision times (Datetime2) and the infoset does
// implying some discrepancies between values read from different storage mechanism.
var theDatesHaveNotBeenModified = DateUtils.DatesAreEquivalent(part.CreatedUtc, part.VersionCreatedUtc);
var theEditorShouldBeBlank =
itemHasNeverBeenPublished &&
@@ -71,7 +76,6 @@ namespace Orchard.Core.Common.DateEditor {
try {
var utcDateTime = _dateLocalizationServices.ConvertFromLocalizedString(model.Editor.Date, model.Editor.Time);
part.CreatedUtc = utcDateTime;
part.VersionCreatedUtc = utcDateTime;
}
catch (FormatException) {
updater.AddModelError(Prefix, T("'{0} {1}' could not be parsed as a valid date and time.", model.Editor.Date, model.Editor.Time));
@@ -87,5 +91,6 @@ namespace Orchard.Core.Common.DateEditor {
return model;
});
}
}
}

View File

@@ -1,6 +1,7 @@
using JetBrains.Annotations;
using Orchard.Core.Common.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Utilities;
namespace Orchard.Core.Common.DateEditor {
[UsedImplicitly]
@@ -13,7 +14,7 @@ namespace Orchard.Core.Common.DateEditor {
}
var thisIsTheInitialVersionRecord = part.ContentItem.Version < 2;
var theDatesHaveNotBeenModified = part.CreatedUtc == part.VersionCreatedUtc;
var theDatesHaveNotBeenModified = DateUtils.DatesAreEquivalent(part.CreatedUtc, part.VersionCreatedUtc);
var theContentDateShouldBeUpdated = thisIsTheInitialVersionRecord && theDatesHaveNotBeenModified;
if (theContentDateShouldBeUpdated) {

View File

@@ -49,18 +49,20 @@ namespace Orchard.Core.Common.Handlers {
OnPublishing<CommonPart>(AssignPublishingDates);
OnIndexing<CommonPart>((context, commonPart) => {
var utcNow = _clock.UtcNow;
context.DocumentIndex
.Add("type", commonPart.ContentItem.ContentType).Store()
.Add("created", commonPart.CreatedUtc ?? _clock.UtcNow).Store()
.Add("published", commonPart.PublishedUtc ?? _clock.UtcNow).Store()
.Add("modified", commonPart.ModifiedUtc ?? _clock.UtcNow).Store();
.Add("created", commonPart.CreatedUtc ?? utcNow).Store()
.Add("published", commonPart.PublishedUtc ?? utcNow).Store()
.Add("modified", commonPart.ModifiedUtc ?? utcNow).Store();
if (commonPart.Container != null) {
context.DocumentIndex.Add("container-id", commonPart.Container.Id).Store();
}
if (commonPart.Owner != null) {
context.DocumentIndex.Add("author", commonPart.Owner.UserName).Analyze().Store();
context.DocumentIndex.Add("author", commonPart.Owner.UserName).Store();
}
});
}
@@ -93,6 +95,7 @@ namespace Orchard.Core.Common.Handlers {
protected void AssignCreatingDates(InitializingContentContext context, CommonPart part) {
// assign default create/modified dates
var utcNow = _clock.UtcNow;
part.CreatedUtc = utcNow;
part.ModifiedUtc = utcNow;
part.VersionCreatedUtc = utcNow;
@@ -101,6 +104,7 @@ namespace Orchard.Core.Common.Handlers {
private void AssignUpdateDates(UpdateEditorContext context, CommonPart part) {
var utcNow = _clock.UtcNow;
part.ModifiedUtc = utcNow;
part.VersionModifiedUtc = utcNow;
}
@@ -116,16 +120,17 @@ namespace Orchard.Core.Common.Handlers {
building.VersionPublishedUtc = null;
// assign the created
building.CreatedUtc = existing.CreatedUtc ?? _clock.UtcNow;
building.CreatedUtc = existing.CreatedUtc ?? utcNow;
// persist any published dates
building.PublishedUtc = existing.PublishedUtc;
// assign modified date for the new version
building.ModifiedUtc = _clock.UtcNow;
building.ModifiedUtc = utcNow;
}
protected void AssignPublishingDates(PublishContentContext context, CommonPart part) {
var utcNow = _clock.UtcNow;
part.PublishedUtc = utcNow;
part.VersionPublishedUtc = utcNow;
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Orchard.Core.Common.Utilities {
public class DateUtils {
/// <summary>
/// Compares two <see cref="DateTime" /> instance without their milliseconds portion.
/// </summary>
/// <param name="a">The first <see cref="DateTime" /> to compare.</param>
/// <param name="b">The second <see cref="DateTime" /> to compare.</param>
/// <returns><c>True</c> if the two instances are in the same second, <c>False</c> otherwise.</returns>
public static bool DatesAreEquivalent(DateTime a, DateTime b) {
a = a.ToUniversalTime();
b = b.ToUniversalTime();
return
new DateTime(a.Year, a.Month, a.Day, a.Hour, a.Minute, a.Second) ==
new DateTime(b.Year, b.Month, b.Day, b.Hour, b.Minute, b.Second);
}
/// <summary>
/// Compares two <see cref="DateTime?" /> instance without their milliseconds portion.
/// </summary>
/// <param name="a">The first <see cref="DateTime?" /> to compare.</param>
/// <param name="b">The second <see cref="DateTime?" /> to compare.</param>
/// <returns><c>True</c> if the two instances are in the same second, <c>False</c> otherwise.</returns>
public static bool DatesAreEquivalent(DateTime? a, DateTime? b) {
if (!a.HasValue && !b.HasValue) {
return true;
}
if (a.HasValue != b.HasValue) {
return false;
}
return DatesAreEquivalent(a.Value, b.Value);
}
}
}

View File

@@ -22,8 +22,11 @@ namespace Orchard.Core.Contents.Controllers {
public Localizer T { get; set; }
// /Contents/Item/Display/72
public ActionResult Display(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
public ActionResult Display(int? id) {
if (id == null)
return HttpNotFound();
var contentItem = _contentManager.Get(id.Value, VersionOptions.Published);
if (contentItem == null)
return HttpNotFound();
@@ -38,13 +41,16 @@ namespace Orchard.Core.Contents.Controllers {
// /Contents/Item/Preview/72
// /Contents/Item/Preview/72?version=5
public ActionResult Preview(int id, int? version) {
public ActionResult Preview(int? id, int? version) {
if (id == null)
return HttpNotFound();
var versionOptions = VersionOptions.Latest;
if (version != null)
versionOptions = VersionOptions.Number((int)version);
var contentItem = _contentManager.Get(id, versionOptions);
var contentItem = _contentManager.Get(id.Value, versionOptions);
if (contentItem == null)
return HttpNotFound();

View File

@@ -94,6 +94,7 @@
<Compile Include="Common\DateEditor\DateEditorViewModel.cs" />
<Compile Include="Common\Settings\TextFieldSettingsEvents.cs" />
<Compile Include="Common\Settings\TextFieldSettings.cs" />
<Compile Include="Common\Utilities\DateUtils.cs" />
<Compile Include="Common\ViewModels\DateTimeEditor.cs" />
<Compile Include="Common\ViewModels\TextFieldDriverViewModel.cs" />
<Compile Include="Common\ViewModels\TextFieldSettingsEventsViewModel.cs" />

View File

@@ -42,6 +42,7 @@ namespace Orchard.Core.Scheduling.Services {
foreach (var taskEntry in taskEntries) {
_transactionManager.RequireNew();
_contentManager.Clear();
try {
// fetch the task

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Orchard.Core.Settings.Descriptor.Records;
using Orchard.Data;
@@ -8,13 +7,14 @@ using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions.Models;
using Orchard.Localization;
using Orchard.Logging;
using System.Linq;
namespace Orchard.Core.Settings.Descriptor {
public class ShellDescriptorManager : IShellDescriptorManager {
public class ShellDescriptorManager : Component, IShellDescriptorManager {
private readonly IRepository<ShellDescriptorRecord> _shellDescriptorRepository;
private readonly IShellDescriptorManagerEventHandler _events;
private readonly ShellSettings _shellSettings;
private ShellDescriptorRecord _shellDescriptorRecord;
public ShellDescriptorManager(
IRepository<ShellDescriptorRecord> shellDescriptorRepository,
@@ -23,11 +23,8 @@ namespace Orchard.Core.Settings.Descriptor {
_shellDescriptorRepository = shellDescriptorRepository;
_events = events;
_shellSettings = shellSettings;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public ShellDescriptor GetShellDescriptor() {
ShellDescriptorRecord shellDescriptorRecord = GetDescriptorRecord();
if (shellDescriptorRecord == null) return null;
@@ -56,11 +53,7 @@ namespace Orchard.Core.Settings.Descriptor {
}
private ShellDescriptorRecord GetDescriptorRecord() {
if (_shellDescriptorRecord == null) {
return _shellDescriptorRecord = _shellDescriptorRepository.Table.ToList().SingleOrDefault();
}
return _shellDescriptorRecord;
return _shellDescriptorRepository.Get(x => x != null);
}
public void UpdateShellDescriptor(int priorSerialNumber, IEnumerable<ShellFeature> enabledFeatures, IEnumerable<ShellParameter> parameters) {
@@ -69,6 +62,8 @@ namespace Orchard.Core.Settings.Descriptor {
if (priorSerialNumber != serialNumber)
throw new InvalidOperationException(T("Invalid serial number for shell descriptor").ToString());
Logger.Information("Updating shell descriptor for shell '{0}'...", _shellSettings.Name);
if (shellDescriptorRecord == null) {
shellDescriptorRecord = new ShellDescriptorRecord { SerialNumber = 1 };
_shellDescriptorRepository.Create(shellDescriptorRecord);
@@ -76,13 +71,12 @@ namespace Orchard.Core.Settings.Descriptor {
else {
shellDescriptorRecord.SerialNumber++;
}
_shellDescriptorRecord = shellDescriptorRecord;
shellDescriptorRecord.Features.Clear();
foreach (var feature in enabledFeatures) {
shellDescriptorRecord.Features.Add(new ShellFeatureRecord { Name = feature.Name, ShellDescriptorRecord = shellDescriptorRecord });
}
Logger.Debug("Enabled features for shell '{0}' set: {1}.", _shellSettings.Name, String.Join(", ", enabledFeatures.Select(feature => feature.Name)));
shellDescriptorRecord.Parameters.Clear();
@@ -94,6 +88,9 @@ namespace Orchard.Core.Settings.Descriptor {
ShellDescriptorRecord = shellDescriptorRecord
});
}
Logger.Debug("Parameters for shell '{0}' set: {1}.", _shellSettings.Name, String.Join(", ", parameters.Select(parameter => parameter.Name + "-" + parameter.Value)));
Logger.Information("Shell descriptor updated for shell '{0}'.", _shellSettings.Name);
_events.Changed(GetShellDescriptorFromRecord(shellDescriptorRecord), _shellSettings.Name);
}

View File

@@ -137,28 +137,25 @@
var _this = $(this);
var _controllees = $("[data-controllerid=" + _this.attr("id") + "]");
var hide = true;
_controllees.each(function () {
var _controllee = $(this);
var hidden = _controllee.attr("data-defaultstate") == "hidden";
var _controlleeIsHidden = _controllee.is(":hidden");
if (_this.is(":checked") || _this.is(":selected")) {
hide = hidden;
}
else {
hide = !hidden;
}
var hiddenByDefault = _controllee.attr("data-defaultstate") == "hidden";
var checkedOrSelected = _this.is(":checked") || _this.is(":selected");
if (!hide) {
if (_controlleeIsHidden) {
if (checkedOrSelected) {
if (!hiddenByDefault) {
_controllee.hide().show(); // <- unhook this when the following comment applies
// _controllees.slideUp(200); // <- hook this back up when chrome behaves, or when I care less...or when chrome behaves
} else {
_controllee.hide();
}
} else {
if (!hiddenByDefault) {
_controllee.hide();
} else {
_controllee.show();
}
} else if (!_controlleeIsHidden) {
// _controllees.slideUp(200); // <- hook this back up when chrome behaves, or when I care less...or when chrome behaves
_controllee.hide()
}
});
@@ -175,26 +172,16 @@
return;
}
controller.data("isControlling", 1);
if (!controller.is(":checked") && !controller.is(":selected")) {
$("[data-controllerid=" + controller.attr("id") + "]").hide();
}
if (controller.is(":checkbox")) {
controller.click($(this).toggleWhatYouControl);
controller.click($(this).toggleWhatYouControl).each($(this).toggleWhatYouControl);
} else if (controller.is(":radio")) {
$("[name=" + controller.attr("name") + "]").click(function () { $("[name=" + $(this).attr("name") + "]").each($(this).toggleWhatYouControl); });
}
else if (controller.is("option")) {
controller.parent().change(function () {
controller.toggleWhatYouControl();
});
}).each($(this).toggleWhatYouControl);
}
// if data-defaultstate is 'hidden' hide it by default
var hidden = $(this).attr("data-defaultstate") == "hidden";
if (hidden) {
$(this).hide();
}
});
});
// inline form link buttons (form.inline.link button) swapped out for a link that submits said form

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Routing;
using Orchard.Alias.Implementation.Holder;
using Orchard.Alias.Implementation.Storage;
using Orchard.Mvc.Routes;
using Orchard.Utility.Extensions;
@@ -13,12 +14,15 @@ namespace Orchard.Alias.Implementation {
private readonly IAliasStorage _aliasStorage;
private readonly IEnumerable<IRouteProvider> _routeProviders;
private readonly Lazy<IEnumerable<RouteDescriptor>> _routeDescriptors;
private readonly IAliasHolder _aliasHolder;
public DefaultAliasService(
IAliasStorage aliasStorage,
IEnumerable<IRouteProvider> routeProviders) {
IEnumerable<IRouteProvider> routeProviders,
IAliasHolder aliasHolder) {
_aliasStorage = aliasStorage;
_routeProviders = routeProviders;
_aliasHolder = aliasHolder;
_routeDescriptors = new Lazy<IEnumerable<RouteDescriptor>>(GetRouteDescriptors);
}
@@ -79,7 +83,37 @@ namespace Orchard.Alias.Implementation {
}
public IEnumerable<string> Lookup(RouteValueDictionary routeValues) {
return List().Where(item => item.Item2.Match(routeValues)).Select(item=>item.Item1).ToList();
object area;
if (routeValues.TryGetValue("area", out area)) {
// the route has an area, lookup in the specific alias map
var map = _aliasHolder.GetMap(area.ToString());
if (map == null) {
return Enumerable.Empty<string>();
}
var locate = map.Locate(routeValues);
if (locate == null) {
return Enumerable.Empty<string>();
}
return new[] { locate.Item2 };
}
// no specific area, lookup in all alias maps
var result = new List<string>();
foreach (var map in _aliasHolder.GetMaps()) {
var locate = map.Locate(routeValues);
if (locate != null) {
result.Add(locate.Item2);
}
}
return result;
}
public IEnumerable<Tuple<string, RouteValueDictionary>> List() {

View File

@@ -0,0 +1,40 @@
using System;
using System.Linq;
using Orchard.Alias.Implementation.Holder;
using Orchard.Alias.Implementation.Storage;
using Orchard.Environment;
using Orchard.Tasks;
using Orchard.Logging;
namespace Orchard.Alias.Implementation.Updater {
public class AliasHolderUpdaterTask : IOrchardShellEvents, IBackgroundTask {
private readonly IAliasHolderUpdater _aliasHolderUpdater;
public ILogger Logger { get; set; }
public AliasHolderUpdaterTask(IAliasHolderUpdater aliasHolderUpdater) {
_aliasHolderUpdater = aliasHolderUpdater;
Logger = NullLogger.Instance;
}
void IOrchardShellEvents.Activated() {
Refresh();
}
void IOrchardShellEvents.Terminating() {
}
private void Refresh() {
try {
_aliasHolderUpdater.Refresh();
}
catch (Exception ex) {
Logger.Error(ex, "Exception during Alias refresh");
}
}
public void Sweep() {
Refresh();
}
}
}

View File

@@ -76,6 +76,7 @@
<Content Include="Views\Admin\Edit.cshtml" />
<Content Include="Views\Admin\Index.cshtml" />
<Content Include="Web.config" />
<Compile Include="Implementation\Updater\AliasHolderUpdater.cs" />
<Compile Include="Implementation\Updater\AliasUpdateCursor.cs" />
<Compile Include="Implementation\Updater\AliasUpdaterBackgroundTask.cs" />
<Compile Include="Implementation\Updater\IAliasUpdateCursor.cs" />
@@ -103,7 +104,7 @@
<Compile Include="Implementation\Holder\IAliasHolder.cs" />
<Compile Include="Implementation\Map\AliasMap.cs" />
<Compile Include="Implementation\Storage\AliasStorage.cs" />
<Compile Include="Implementation\Updater\AliasHolderUpdater.cs" />
<Compile Include="Implementation\Updater\AliasHolderUpdaterTask.cs" />
<Compile Include="Implementation\Utils.cs" />
<Compile Include="Migrations.cs" />
<Compile Include="Records\ActionRecord.cs" />

View File

@@ -80,6 +80,13 @@ namespace Orchard.Autoroute.Handlers {
part.DisplayAlias = _autorouteService.Value.GenerateAlias(part);
}
// if the generated alias is empty, compute a new one
if (String.IsNullOrWhiteSpace(part.DisplayAlias)) {
_autorouteService.Value.ProcessPath(part);
_orchardServices.Notifier.Warning(T("The permalink could not be generated, a new slug has been defined: \"{0}\"", part.Path));
return;
}
// should it become the home page ?
if (part.DisplayAlias != "/" && _orchardServices.Authorizer.Authorize(Permissions.SetHomePage)) {
// if it's the current home page, do nothing

View File

@@ -89,6 +89,7 @@ namespace Orchard.Azure.MediaServices.Services.Assets {
pendingAsset.UploadState.BytesComplete = 0;
pendingAsset.UploadState.CompletedUtc = null;
_transactionManager.RequireNew();
_contentManager.Clear();
var assetProgressMoniker = Guid.NewGuid();
var assetCancellationTokenSource = new CancellationTokenSource();
@@ -185,6 +186,7 @@ namespace Orchard.Azure.MediaServices.Services.Assets {
if ((_clock.UtcNow - lastUpdateUtc).Seconds >= 5) {
progressAsset.UploadState.BytesComplete = progressInfo.Data.BytesTransferred;
_transactionManager.RequireNew();
_contentManager.Clear();
lastUpdateUtc = _clock.UtcNow;
}

View File

@@ -31,7 +31,7 @@ namespace Orchard.Comments.Models {
set { Record.UserName = value; }
}
[RegularExpression(@"^(?![\.@])(""([^""\r\\]|\\[""\r\\])*""|([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$")]
[RegularExpression(@"^(?![\.@])(""([^""\r\\]|\\[""\r\\])*""|([-\w!#$%&'*+/=?^`{|}~]|(?<!\.)\.)*)(?<!\.)@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$")]
public string Email {
get { return Record.Email; }
set { Record.Email = value; }

View File

@@ -139,7 +139,13 @@ namespace Orchard.DesignerTools.Services {
}
foreach (var member in members) {
if (o is ContentItem && member.Name == "ContentManager"
if ((o is ContentItem && (member.Name == "ContentManager"
|| member.Name == "Parts"
|| member.Name == "Record"
|| member.Name == "VersionRecord"
|| member.Name == "TypeDefinition"
|| member.Name == "TypePartDefinition"
|| member.Name == "PartDefinition"))
|| o is Delegate
|| o is Type
) {

View File

@@ -33,6 +33,7 @@ namespace Orchard.Indexing.Services {
private readonly ShellSettings _shellSettings;
private readonly ILockFileManager _lockFileManager;
private readonly IClock _clock;
private readonly ITransactionManager _transactionManager;
private const int ContentItemsPerLoop = 50;
private IndexingStatus _indexingStatus = IndexingStatus.Idle;
@@ -44,7 +45,8 @@ namespace Orchard.Indexing.Services {
IAppDataFolder appDataFolder,
ShellSettings shellSettings,
ILockFileManager lockFileManager,
IClock clock) {
IClock clock,
ITransactionManager transactionManager) {
_taskRepository = taskRepository;
_contentRepository = contentRepository;
_indexManager = indexManager;
@@ -52,6 +54,7 @@ namespace Orchard.Indexing.Services {
_appDataFolder = appDataFolder;
_shellSettings = shellSettings;
_lockFileManager = lockFileManager;
_transactionManager = transactionManager;
_clock = clock;
Logger = NullLogger.Instance;
}
@@ -143,34 +146,38 @@ namespace Orchard.Indexing.Services {
private bool BatchIndex(string indexName, string settingsFilename, IndexSettings indexSettings) {
var addToIndex = new List<IDocumentIndex>();
var deleteFromIndex = new List<int>();
bool loop = false;
// Rebuilding the index ?
if (indexSettings.Mode == IndexingMode.Rebuild) {
Logger.Information("Rebuilding index");
_indexingStatus = IndexingStatus.Rebuilding;
// load all content items
var contentItems = _contentRepository
do {
loop = true;
// load all content items
var contentItems = _contentRepository
.Table.Where(versionRecord => versionRecord.Latest && versionRecord.Id > indexSettings.LastContentId)
.OrderBy(versionRecord => versionRecord.Id)
.Take(ContentItemsPerLoop)
.ToList()
.Select(versionRecord => _contentManager.Get(versionRecord.ContentItemRecord.Id, VersionOptions.VersionRecord(versionRecord.Id)))
.Distinct()
.ToList();
.OrderBy(versionRecord => versionRecord.Id)
.Take(ContentItemsPerLoop)
.ToList()
.Select(versionRecord => _contentManager.Get(versionRecord.ContentItemRecord.Id, VersionOptions.VersionRecord(versionRecord.Id)))
.Distinct()
.ToList();
// if no more elements to index, switch to update mode
if (contentItems.Count == 0) {
indexSettings.Mode = IndexingMode.Update;
}
// if no more elements to index, switch to update mode
if (contentItems.Count == 0) {
indexSettings.Mode = IndexingMode.Update;
}
foreach (var item in contentItems) {
try {
foreach (var item in contentItems) {
try {
var settings = GetTypeIndexingSettings(item);
var settings = GetTypeIndexingSettings(item);
// skip items from types which are not indexed
if (settings.List.Contains(indexName)) {
if (settings.List.Contains(indexName)) {
if (item.HasPublished()) {
var published = _contentManager.Get(item.Id, VersionOptions.Published);
IDocumentIndex documentIndex = ExtractDocumentIndex(published);
@@ -181,66 +188,88 @@ namespace Orchard.Indexing.Services {
}
}
else if (settings.List.Contains(indexName + ":latest")) {
IDocumentIndex documentIndex = ExtractDocumentIndex(item);
IDocumentIndex documentIndex = ExtractDocumentIndex(item);
if (documentIndex != null && documentIndex.IsDirty) {
addToIndex.Add(documentIndex);
if (documentIndex != null && documentIndex.IsDirty) {
addToIndex.Add(documentIndex);
}
}
}
indexSettings.LastContentId = item.VersionRecord.Id;
indexSettings.LastContentId = item.VersionRecord.Id;
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", item.Id);
}
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", item.Id);
if (contentItems.Count < ContentItemsPerLoop) {
loop = false;
}
}
else {
_transactionManager.RequireNew();
_contentManager.Clear();
}
} while (loop);
}
if (indexSettings.Mode == IndexingMode.Update) {
Logger.Information("Updating index");
_indexingStatus = IndexingStatus.Updating;
var indexingTasks = _taskRepository
.Table.Where(x => x.Id > indexSettings.LastIndexedId)
.OrderBy(x => x.Id)
.Take(ContentItemsPerLoop)
.ToList()
.GroupBy(x => x.ContentItemRecord.Id)
do {
var indexingTasks = _taskRepository
.Table.Where(x => x.Id > indexSettings.LastIndexedId)
.OrderBy(x => x.Id)
.Take(ContentItemsPerLoop)
.ToList()
.GroupBy(x => x.ContentItemRecord.Id)
.Select(group => new { TaskId = group.Max(task => task.Id), Delete = group.Last().Action == IndexingTaskRecord.Delete, Id = group.Key, ContentItem = _contentManager.Get(group.Key, VersionOptions.Latest) })
.OrderBy(x => x.TaskId)
.ToArray();
.OrderBy(x => x.TaskId)
.ToArray();
foreach (var item in indexingTasks) {
try {
foreach (var item in indexingTasks) {
try {
IDocumentIndex documentIndex = null;
IDocumentIndex documentIndex = null;
// item.ContentItem can be null if the content item has been deleted
if (item.ContentItem != null) {
// skip items from types which are not indexed
var settings = GetTypeIndexingSettings(item.ContentItem);
if (settings.List.Contains(indexName)) {
documentIndex = ExtractDocumentIndex(item.ContentItem);
}
// item.ContentItem can be null if the content item has been deleted
if (item.ContentItem != null) {
// skip items from types which are not indexed
var settings = GetTypeIndexingSettings(item.ContentItem);
if (settings.List.Contains(indexName)) {
documentIndex = ExtractDocumentIndex(item.ContentItem);
}
else if (settings.List.Contains(indexName + ":latest")) {
var latest = _contentManager.Get(item.Id, VersionOptions.Latest);
documentIndex = ExtractDocumentIndex(latest);
}
}
}
if (documentIndex == null || item.Delete) {
deleteFromIndex.Add(item.Id);
}
else if (documentIndex.IsDirty) {
addToIndex.Add(documentIndex);
}
if (documentIndex == null || item.Delete) {
deleteFromIndex.Add(item.Id);
}
else if (documentIndex.IsDirty) {
addToIndex.Add(documentIndex);
}
indexSettings.LastIndexedId = item.TaskId;
indexSettings.LastIndexedId = item.TaskId;
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to index content item #{0} during update", item.Id);
}
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to index content item #{0} during update", item.Id);
if (indexingTasks.Length < ContentItemsPerLoop) {
loop = false;
}
else {
_transactionManager.RequireNew();
_contentManager.Clear();
}
}
while (loop);
}
// save current state of the index

View File

@@ -8,6 +8,6 @@ namespace Orchard.Localization.ViewModels {
[Required]
public string SelectedCulture { get; set; }
public IEnumerable<string> SiteCultures { get; set; }
public IContent Content { get; set; }
public dynamic Content { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
@model Orchard.Localization.ViewModels.AddLocalizationViewModel
@using Orchard.ContentManagement;
@{
Style.Require("LocalizationAdmin");
}
@@ -11,6 +12,6 @@
<div>
@T("This is the <em>{0}</em> variation of {1}",
Html.DropDownList("SelectedCulture", new SelectList(siteCultures, Model.SelectedCulture)),
Html.ItemEditLink(Model.Content))
Html.ItemEditLink((ContentItem)Model.Content.ContentItem))
</div>
</fieldset>

View File

@@ -137,7 +137,7 @@ namespace Orchard.MediaProcessing.Services {
descriptor.Filter(filterContext);
}
_fileNameProvider.UpdateFileName(profileName, path, filterContext.FilePath);
_fileNameProvider.UpdateFileName(profileName, System.Web.HttpUtility.UrlDecode(path), filterContext.FilePath);
if (!filterContext.Saved) {
try {

View File

@@ -1,4 +1,6 @@
using System.Linq;
using System;
using System.Linq;
using System.Text.RegularExpressions;
using Orchard.Commands;
using Orchard.Environment.Configuration;
using Orchard.MultiTenancy.Services;
@@ -42,6 +44,16 @@ namespace Orchard.MultiTenancy.Commands {
[OrchardSwitches("Host,UrlPrefix")]
public void Create(string tenantName) {
Context.Output.WriteLine(T("Creating tenant"));
if (string.IsNullOrWhiteSpace(tenantName) || !Regex.IsMatch(tenantName, @"^\w+$")) {
Context.Output.WriteLine(T("Invalid tenant name. Must contain characters only and no spaces."));
return;
}
if (_tenantService.GetTenants().Any(tenant => string.Equals(tenant.Name, tenantName, StringComparison.OrdinalIgnoreCase))) {
Context.Output.WriteLine(T("Could not create tenant \"{0}\". A tenant with the same name already exists.", tenantName));
return;
}
_tenantService.CreateTenant(
new ShellSettings {
Name = tenantName,

View File

@@ -9,7 +9,6 @@ using Orchard.MultiTenancy.Services;
using Orchard.MultiTenancy.ViewModels;
using Orchard.Security;
using Orchard.UI.Notify;
using Orchard.Utility.Extensions;
namespace Orchard.MultiTenancy.Controllers {
[ValidateInput(false)]
@@ -52,11 +51,17 @@ namespace Orchard.MultiTenancy.Controllers {
[HttpPost, ActionName("Add")]
public ActionResult AddPOST(TenantAddViewModel viewModel) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't create tenant")))
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't create tenant"))) {
return new HttpUnauthorizedResult();
}
if (!EnsureDefaultTenant())
if (!EnsureDefaultTenant()) {
return new HttpUnauthorizedResult();
}
if (_tenantService.GetTenants().Any(tenant => string.Equals(tenant.Name, viewModel.Name, StringComparison.OrdinalIgnoreCase))) {
ModelState.AddModelError("Name", T("A tenant with the same name already exists.", viewModel.Name).Text);
}
// ensure tenants name are valid
if (!String.IsNullOrEmpty(viewModel.Name) && !Regex.IsMatch(viewModel.Name, @"^\w+$")) {

View File

@@ -27,6 +27,8 @@
<fieldset class="publish-later-datetime">
<legend>@T("Publish")</legend>
@Html.HiddenFor(m => m.Editor.ShowDate)
@Html.HiddenFor(m => m.Editor.ShowTime)
@Html.EditorFor(m => m.Editor)
<button type="submit" name="submit.Save" value="submit.PublishLater">@T("Publish Later")</button>
</fieldset>

View File

@@ -67,8 +67,9 @@ namespace Orchard.Recipes.RecipeHandlers {
};
foreach (var arg in args) {
// Switch?
if (arg[0] == '/') {
if (arg.StartsWith("/")) {
//If arg is not empty and starts with '/'
int index = arg.IndexOf(':');
var switchName = (index < 0 ? arg.Substring(1) : arg.Substring(1, index - 1));
var switchValue = (index < 0 || index >= arg.Length ? string.Empty : arg.Substring(index + 1));

View File

@@ -62,8 +62,8 @@ namespace Orchard.Recipes.RecipeHandlers {
//Create a new transaction for each batch
if (startIndex < elementDictionary.Count) {
_orchardServices.ContentManager.Clear();
_transactionManager.RequireNew();
_orchardServices.ContentManager.Clear();
}
}
}

View File

@@ -1,30 +1,34 @@
<?xml version="1.0"?>
<Orchard>
<Recipe>
<Name>Search</Name>
<Description>Configures a default search index and search settings using the Lucene engine.</Description>
<Author>The Orchard Team</Author>
<WebSite>http://orchardproject.net</WebSite>
<Tags>developer</Tags>
<Version>1.0</Version>
</Recipe>
<Recipe>
<Name>Search</Name>
<Description>Configures a default search index and search settings using the Lucene engine.</Description>
<Author>The Orchard Team</Author>
<WebSite>http://orchardproject.net</WebSite>
<Tags>developer</Tags>
<Version>1.0</Version>
</Recipe>
<Feature enable="Orchard.Search,Lucene" />
<Metadata>
<Types>
<Page TypeIndexing.Indexes="Search">
</Page>
<BlogPost TypeIndexing.Indexes="Search">
</BlogPost>
</Types>
</Metadata>
<Feature enable="Orchard.Search,Lucene" />
<Migration features="*" />
<Command>
index create Search
index update Search
search use Search
</Command>
<Metadata>
<Types>
<Page TypeIndexing.Indexes="Search">
</Page>
<BlogPost TypeIndexing.Indexes="Search">
</BlogPost>
</Types>
</Metadata>
<Migration features="*" />
<Command>
index create Search
index update Search
</Command>
<Settings>
<SearchSettingsPart SearchedFields="body,title" FilterCulture="false" SearchIndex="Search" />
</Settings>
</Orchard>

View File

@@ -49,6 +49,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NHibernate, Version=3.3.1.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\lib\nhibernate\NHibernate.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Data.DataSetExtensions" />

View File

@@ -19,17 +19,20 @@ namespace Orchard.Tags.Services {
private readonly INotifier _notifier;
private readonly IAuthorizationService _authorizationService;
private readonly IOrchardServices _orchardServices;
private readonly ISessionFactoryHolder _sessionFactoryHolder;
public TagService(IRepository<TagRecord> tagRepository,
IRepository<ContentTagRecord> contentTagRepository,
INotifier notifier,
IAuthorizationService authorizationService,
IOrchardServices orchardServices) {
IOrchardServices orchardServices,
ISessionFactoryHolder sessionFactoryHolder) {
_tagRepository = tagRepository;
_contentTagRepository = contentTagRepository;
_notifier = notifier;
_authorizationService = authorizationService;
_orchardServices = orchardServices;
_sessionFactoryHolder = sessionFactoryHolder;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
@@ -207,6 +210,11 @@ namespace Orchard.Tags.Services {
}
contentItem.As<TagsPart>().CurrentTags = tagNamesForContentItem;
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
if (sessionFactory != null)
sessionFactory.EvictCollection("Orchard.Tags.Models.TagsPartRecord.Tags", contentItem.As<TagsPart>().Record.Id);
}
}

View File

@@ -8,6 +8,7 @@ using Orchard.Taxonomies.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Orchard.Taxonomies.Settings;
using System;
namespace Orchard.Taxonomies.Handlers {
[UsedImplicitly]
@@ -23,7 +24,7 @@ namespace Orchard.Taxonomies.Handlers {
OnPublished<TaxonomyPart>((context, part) => {
var previousTermTypeName = part.TermTypeName;
if (previousName == null || part.Name == previousName) {
if (previousName == null) {
// is it a new taxonomy ?
taxonomyService.CreateTermContentType(part);
}

View File

@@ -10,7 +10,7 @@ Features:
Name: Templates
Description: Provides a Template type that represents a shape template, stored as a content item.
Category: Content
Dependencies: Contents, Orchard.Tokens
Dependencies: Contents, Orchard.Tokens, Orchard.Core
Orchard.Templates.Razor:
Name: Razor Templates
Description: Extends Templates with Razor templates.

View File

@@ -176,7 +176,7 @@
<Compile Include="Services\TemplateProcessorImpl.cs" />
<Compile Include="Services\RazorTemplateProcessor.cs" />
<Compile Include="Services\DefaultTemplateService.cs" />
<Compile Include="Services\TemplateShapeDisplayEvent.cs" />
<Compile Include="Services\TemplateShapeBindingResolver.cs" />
<Compile Include="Settings\ShapePartSettings.cs" />
<Compile Include="Settings\ShapePartSettingsEvents.cs" />
<Compile Include="ViewModels\ShapePartSettingsViewModel.cs" />

View File

@@ -0,0 +1,83 @@
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Templates.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
namespace Orchard.Templates.Services {
public class TemplateShapeBindingResolver : IShapeBindingResolver {
private ICacheManager _cacheManager;
private ISignals _signals;
private IContentManager _contentManager;
private ITemplateService _templateService;
public TemplateShapeBindingResolver(
ICacheManager cacheManager,
ISignals signals,
IContentManager contentManager,
ITemplateService templateService
) {
_cacheManager = cacheManager;
_signals = signals;
_contentManager = contentManager;
_templateService = templateService;
}
public bool TryGetDescriptorBinding(string shapeType, out ShapeBinding shapeBinding) {
var processors = BuildShapeProcessors();
TemplateResult templateResult = null;
if (processors.TryGetValue(shapeType, out templateResult)) {
shapeBinding = new ShapeBinding {
BindingName = "Templates",
Binding = ctx => CoerceHtmlString(_templateService.Execute(
templateResult.Template,
templateResult.Name,
templateResult.Processor, ctx.Value))
};
return true;
}
shapeBinding = null;
return false;
}
private IDictionary<string, TemplateResult> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
var allTemplates = _contentManager.Query<ShapePart>().List();
return allTemplates.Select(x => {
var name = x.Name;
var template = x.Template;
var processorName = x.ProcessorName;
return new TemplateResult {
Name = x.Name,
Template = x.Template,
Processor = x.ProcessorName
};
}).ToDictionary(x => x.Name, x => x);
});
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
private class TemplateResult {
public string Name { get; set; }
public string Processor { get; set; }
public string Template { get; set; }
}
}
}

View File

@@ -1,59 +0,0 @@
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Templates.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Orchard.Templates.Services {
public class TemplateShapeDisplayEvent : IShapeDisplayEvents {
private ICacheManager _cacheManager;
private ISignals _signals;
private IContentManager _contentManager;
private ITemplateService _templateService;
public TemplateShapeDisplayEvent(
ICacheManager cacheManager,
ISignals signals,
IContentManager contentManager,
ITemplateService templateService
) {
_cacheManager = cacheManager;
_signals = signals;
_contentManager = contentManager;
_templateService = templateService;
}
public void Displaying(ShapeDisplayingContext context) {
var processors = BuildShapeProcessors();
Func<dynamic, IHtmlString> processor;
if (processors.TryGetValue(context.ShapeMetadata.Type, out processor)) {
context.ChildContent = processor(context.Shape);
}
}
public void Displayed(ShapeDisplayedContext context) {
}
public IDictionary<string, Func<dynamic, IHtmlString>> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
var allTemplates = _contentManager.Query<ShapePart>().List();
return allTemplates.Select(x => new KeyValuePair<string, Func<dynamic, IHtmlString>>(
x.Name,
d => CoerceHtmlString(_templateService.Execute(x.Template, x.Name, x.ProcessorName, d))
)).ToDictionary(x => x.Key, x => x.Value);
});
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Inspections;
using FluentNHibernate.Conventions.Instances;
using NHibernate.Type;
namespace Orchard.Data.Conventions {
public class UtcDateTimeConvention : IPropertyConvention, IPropertyConventionAcceptance {
public void Apply(IPropertyInstance instance) {
instance.CustomType<UtcDateTimeType>();
}
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) {
criteria.Expect(x =>
x.Property.Name.EndsWith("Utc", StringComparison.OrdinalIgnoreCase) && (
x.Property.PropertyType.Equals(typeof(DateTime)) ||
x.Property.PropertyType.Equals(typeof(DateTime?))
)
);
}
}
}

View File

@@ -90,6 +90,8 @@ namespace Orchard.Data.Migration {
// apply update methods to each migration class for the module
foreach (var migration in migrations) {
_transactionManager.RequireNew();
// copy the object for the Linq query
var tempMigration = migration;
@@ -102,8 +104,6 @@ namespace Orchard.Data.Migration {
}
try {
_transactionManager.RequireNew();
// do we need to call Create() ?
if (current == 0) {
// try to resolve a Create method

View File

@@ -91,6 +91,7 @@ namespace Orchard.Data.Providers {
.Conventions.Setup(x => x.Add(AutoImport.Never()))
.Conventions.Add(new RecordTableNameConvention(recordDescriptors))
.Conventions.Add(new CacheConventions(recordDescriptors))
.Conventions.Add(new UtcDateTimeConvention())
.Alterations(alt => {
foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) {
alt.Add(new AutoMappingOverrideAlteration(recordAssembly));

View File

@@ -142,6 +142,10 @@ namespace Orchard.Data {
var pathName = GetPathName(_shellSettings.Name);
hash.AddString(_appDataFolder.MapPath(pathName).ToLowerInvariant());
// Orchard version, to rebuild the mappings for each new version
var orchardVersion = new System.Reflection.AssemblyName(typeof(Orchard.ContentManagement.ContentItem).Assembly.FullName).Version.ToString();
hash.AddString(orchardVersion);
// Shell settings data
hash.AddString(_shellSettings.DataProvider);
hash.AddString(_shellSettings.DataTablePrefix);

View File

@@ -15,8 +15,6 @@ namespace Orchard.Data {
private readonly ISessionFactoryHolder _sessionFactoryHolder;
private readonly IEnumerable<ISessionInterceptor> _interceptors;
private ISession _session;
private ITransaction _transaction;
private bool _cancelled;
public SessionLocator(
ISessionFactoryHolder sessionFactoryHolder,
@@ -32,19 +30,13 @@ namespace Orchard.Data {
public ISession For(Type entityType) {
Logger.Debug("Acquiring session for {0}", entityType);
((ITransactionManager)this).Demand();
Demand();
return _session;
}
public void Demand() {
EnsureSession();
if (_transaction == null) {
Logger.Debug("Creating transaction on Demand");
_transaction = _session.BeginTransaction(IsolationLevel);
}
EnsureSession(IsolationLevel);
}
public void RequireNew() {
@@ -52,71 +44,48 @@ namespace Orchard.Data {
}
public void RequireNew(IsolationLevel level) {
EnsureSession();
if (_cancelled) {
if (_transaction != null) {
_transaction.Rollback();
_transaction.Dispose();
_transaction = null;
}
_cancelled = false;
}
else {
if (_transaction != null) {
_transaction.Commit();
}
}
Logger.Debug("Creating new transaction with isolation level {0}", level);
_transaction = _session.BeginTransaction(level);
DisposeSession();
EnsureSession(level);
}
public void Cancel() {
Logger.Debug("Transaction cancelled flag set");
_cancelled = true;
if (_session!= null && !_session.Transaction.WasRolledBack && _session.Transaction.IsActive) {
Logger.Debug("Rolling back transaction");
_session.Transaction.Rollback();
}
}
public void Dispose() {
if (_transaction != null) {
try {
if (!_cancelled) {
Logger.Debug("Marking transaction as complete");
_transaction.Commit();
}
else {
Logger.Debug("Reverting operations from transaction");
_transaction.Rollback();
}
}
catch (Exception e) {
Logger.Error(e, "Error while disposing the transaction.");
}
finally {
_transaction.Dispose();
Logger.Debug("Transaction disposed");
_transaction = null;
_cancelled = false;
}
}
if (_session != null) {
_session.Dispose();
_session = null;
}
DisposeSession();
}
private void EnsureSession() {
private void DisposeSession() {
if (_session != null) {
try {
if (!_session.Transaction.WasRolledBack && _session.Transaction.IsActive) {
Logger.Debug("Committing transaction");
_session.Transaction.Commit();
}
}
finally {
Logger.Debug("Disposing session");
_session.Close();
_session.Dispose();
_session = null;
}
}
}
private void EnsureSession(IsolationLevel level) {
if (_session != null) {
return;
}
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
Logger.Information("Opening database session");
Logger.Debug("Opening NHibernate session");
_session = sessionFactory.OpenSession(new OrchardSessionInterceptor(_interceptors.ToArray(), Logger));
_session.BeginTransaction(level);
}
class OrchardSessionInterceptor : IInterceptor {

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.DisplayManagement {
public interface IShapeBindingResolver : IDependency {
bool TryGetDescriptorBinding(string shapeType, out ShapeBinding shapeBinding);
}
}

View File

@@ -18,6 +18,7 @@ namespace Orchard.DisplayManagement.Implementation {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IEnumerable<IShapeDisplayEvents> _shapeDisplayEvents;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IEnumerable<IShapeBindingResolver> _shapeBindingResolvers;
// this need to be Shape instead of IShape - cast to interface throws error on clr types like HtmlString
private static readonly CallSite<Func<CallSite, object, Shape>> _convertAsShapeCallsite = CallSite<Func<CallSite, object, Shape>>.Create(
@@ -30,12 +31,15 @@ namespace Orchard.DisplayManagement.Implementation {
public DefaultDisplayManager(
IWorkContextAccessor workContextAccessor,
IEnumerable<IShapeDisplayEvents> shapeDisplayEvents,
IEnumerable<IShapeBindingResolver> shapeBindingResolvers,
IHttpContextAccessor httpContextAccessor,
Lazy<IShapeTableLocator> shapeTableLocator) {
_shapeTableLocator = shapeTableLocator;
_workContextAccessor = workContextAccessor;
_shapeDisplayEvents = shapeDisplayEvents;
_httpContextAccessor = httpContextAccessor;
_shapeBindingResolvers = shapeBindingResolvers;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
@@ -135,12 +139,19 @@ namespace Orchard.DisplayManagement.Implementation {
return shape.Metadata.ChildContent;
}
static bool TryGetDescriptorBinding(string shapeType, IEnumerable<string> shapeAlternates, ShapeTable shapeTable, out ShapeBinding shapeBinding) {
private bool TryGetDescriptorBinding(string shapeType, IEnumerable<string> shapeAlternates, ShapeTable shapeTable, out ShapeBinding shapeBinding) {
// shape alternates are optional, fully qualified binding names
// the earliest added alternates have the lowest priority
// the descriptor returned is based on the binding that is matched, so it may be an entirely
// different descriptor if the alternate has a different base name
foreach (var shapeAlternate in shapeAlternates.Reverse()) {
foreach (var shapeBindingResolver in _shapeBindingResolvers) {
if(shapeBindingResolver.TryGetDescriptorBinding(shapeAlternate, out shapeBinding)) {
return true;
}
}
if (shapeTable.Bindings.TryGetValue(shapeAlternate, out shapeBinding)) {
return true;
}
@@ -151,6 +162,12 @@ namespace Orchard.DisplayManagement.Implementation {
// so the shapetype itself may contain a longer alternate forms that falls back to a shorter one
var shapeTypeScan = shapeType;
for (; ; ) {
foreach (var shapeBindingResolver in _shapeBindingResolvers) {
if (shapeBindingResolver.TryGetDescriptorBinding(shapeTypeScan, out shapeBinding)) {
return true;
}
}
if (shapeTable.Bindings.TryGetValue(shapeTypeScan, out shapeBinding)) {
return true;
}

View File

@@ -19,13 +19,13 @@ namespace Orchard.Environment.Configuration {
}
IEnumerable<ShellSettings> IShellSettingsManager.LoadSettings() {
Logger.Debug("Reading ShellSettings...");
Logger.Information("Reading ShellSettings...");
var settingsList = LoadSettingsInternal().ToArray();
var tenantNamesQuery =
from settings in settingsList
select settings.Name;
Logger.Debug("Returning {0} ShellSettings objects for tenants {1}.", tenantNamesQuery.Count(), String.Join(", ", tenantNamesQuery));
Logger.Information("Returning {0} ShellSettings objects for tenants {1}.", tenantNamesQuery.Count(), String.Join(", ", tenantNamesQuery));
return settingsList;
}
@@ -36,11 +36,11 @@ namespace Orchard.Environment.Configuration {
if (String.IsNullOrEmpty(settings.Name))
throw new ArgumentException("The Name property of the supplied ShellSettings object is null or empty; the settings cannot be saved.", "settings");
Logger.Debug("Saving ShellSettings for tenant '{0}'...", settings.Name);
Logger.Information("Saving ShellSettings for tenant '{0}'...", settings.Name);
var filePath = Path.Combine(Path.Combine("Sites", settings.Name), _settingsFileName);
_appDataFolder.CreateFile(filePath, ShellSettingsSerializer.ComposeSettings(settings));
Logger.Debug("ShellSettings saved successfully; flagging tenant '{0}' for restart.", settings.Name);
Logger.Information("ShellSettings saved successfully; flagging tenant '{0}' for restart.", settings.Name);
_events.Saved(settings);
}

View File

@@ -15,11 +15,9 @@ namespace Orchard.FileSystems.Dependencies {
/// </summary>
public class DynamicModuleVirtualPathProvider : VirtualPathProvider, ICustomVirtualPathProvider {
private readonly IExtensionDependenciesManager _extensionDependenciesManager;
private readonly IEnumerable<IExtensionLoader> _loaders;
public DynamicModuleVirtualPathProvider(IExtensionDependenciesManager extensionDependenciesManager, IEnumerable<IExtensionLoader> loaders) {
public DynamicModuleVirtualPathProvider(IExtensionDependenciesManager extensionDependenciesManager) {
_extensionDependenciesManager = extensionDependenciesManager;
_loaders = loaders;
Logger = NullLogger.Instance;
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orchard.FileSystems.Media {
public static class StorageProviderExtensions {
public static void WriteAllText(this IStorageProvider storageProvider, string path, string contents) {
if (storageProvider.FileExists(path)) {
storageProvider.DeleteFile(path);
}
var file = storageProvider.CreateFile(path);
using (var stream = file.OpenWrite())
using (var streamWriter = new StreamWriter(stream)) {
streamWriter.Write(contents);
}
}
public static string ReadAllText(this IStorageProvider storageProvider, string path) {
if (!storageProvider.FileExists(path)) {
return String.Empty;
}
var file = storageProvider.GetFile(path);
using (var stream = file.OpenRead())
using (var streamReader = new StreamReader(stream)) {
return streamReader.ReadToEnd();
}
}
}
}

View File

@@ -171,6 +171,7 @@
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
<Compile Include="Data\AbstractSessionInterceptor.cs" />
<Compile Include="Data\Bags\SArray.cs" />
<Compile Include="Data\Conventions\UtcDateTimeConvention.cs" />
<Compile Include="Data\FetchRequest.cs" />
<Compile Include="Data\Migration\Interpreters\MySqlCommandInterpreter.cs" />
<Compile Include="Data\Providers\MySqlStatementProvider.cs" />
@@ -207,6 +208,7 @@
<Compile Include="DisplayManagement\Implementation\IShapeDisplayEvents.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeFactoryEvents.cs" />
<Compile Include="DisplayManagement\INamedEnumerable.cs" />
<Compile Include="DisplayManagement\IShapeBindingResolver.cs" />
<Compile Include="DisplayManagement\IShapeDisplay.cs" />
<Compile Include="DisplayManagement\ShapeDisplay.cs" />
<Compile Include="DisplayManagement\Shapes\Composite.cs" />
@@ -256,6 +258,7 @@
<Compile Include="FileSystems\Media\ConfigurationMimeTypeProvider.cs" />
<Compile Include="FileSystems\Media\FileSystemStorageProvider.cs" />
<Compile Include="FileSystems\Media\IMimeTypeProvider.cs" />
<Compile Include="FileSystems\Media\StorageProviderExtensions.cs" />
<Compile Include="Indexing\ISearchBits.cs" />
<Compile Include="Localization\HtmlLocalizationExtensions.cs" />
<Compile Include="Localization\Models\DateLocalizationOptions.cs" />

View File

@@ -2,7 +2,9 @@ using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.Data;
using Orchard.Environment.Configuration;
using Orchard.Logging;
using Orchard.ContentManagement;
namespace Orchard.Tasks {
@@ -14,10 +16,18 @@ namespace Orchard.Tasks {
public class BackgroundService : IBackgroundService {
private readonly IEnumerable<IBackgroundTask> _tasks;
private readonly ITransactionManager _transactionManager;
private readonly string _shellName;
private readonly IContentManager _contentManager;
public BackgroundService(IEnumerable<IBackgroundTask> tasks, ITransactionManager transactionManager) {
public BackgroundService(
IEnumerable<IBackgroundTask> tasks,
ITransactionManager transactionManager,
ShellSettings shellSettings,
IContentManager contentManager) {
_tasks = tasks;
_transactionManager = transactionManager;
_shellName = shellSettings.Name;
_contentManager = contentManager;
Logger = NullLogger.Instance;
}
@@ -26,14 +36,14 @@ namespace Orchard.Tasks {
public void Sweep() {
foreach(var task in _tasks) {
try {
_contentManager.Clear();
_transactionManager.RequireNew();
task.Sweep();
}
catch (Exception e) {
_transactionManager.Cancel();
Logger.Error(e, "Error while processing background task");
Logger.Error(e, "Error while processing background task on tenant '{0}'.", _shellName);
}
}
}
}