Swapped out Orchard.Core's Common Routable for the work in progress replacement, Orchard.Core's Routable (seperate core module now)

--HG--
branch : dev
This commit is contained in:
Nathan Heskew
2010-07-13 02:52:02 -07:00
parent 1ff677d24d
commit 501d72afab
46 changed files with 217 additions and 582 deletions

View File

@@ -10,9 +10,10 @@ using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records; using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Common.Services; using Orchard.Core.Routable.Handlers;
using Orchard.Core.Routable.Models;
using Orchard.Core.Routable.Services;
using Orchard.Tests.Modules; using Orchard.Tests.Modules;
using Orchard.Core.Common.Handlers;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using Orchard.Tests.Stubs; using Orchard.Tests.Stubs;
@@ -37,7 +38,7 @@ namespace Orchard.Core.Tests.Common.Services {
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>(); builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
builder.RegisterInstance(new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData()))).As<UrlHelper>(); builder.RegisterInstance(new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData()))).As<UrlHelper>();
builder.RegisterType<RoutableAspectHandler>().As<IContentHandler>(); builder.RegisterType<RoutableHandler>().As<IContentHandler>();
} }
@@ -48,11 +49,11 @@ namespace Orchard.Core.Tests.Common.Services {
var contentManager = _container.Resolve<IContentManager>(); var contentManager = _container.Resolve<IContentManager>();
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = "Please do not use any of the following characters in your slugs: \":\", \"/\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\""; t.Title = "Please do not use any of the following characters in your slugs: \":\", \"/\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\"";
}); });
_routableService.FillSlug(thing.As<RoutableAspect>()); _routableService.FillSlug(thing.As<IsRoutable>());
Assert.That(thing.Slug, Is.EqualTo("please-do-not-use-any-of-the-following-characters-in-your-slugs-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"")); Assert.That(thing.Slug, Is.EqualTo("please-do-not-use-any-of-the-following-characters-in-your-slugs-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\""));
} }
@@ -84,11 +85,11 @@ namespace Orchard.Core.Tests.Common.Services {
veryVeryLongTitle += "aaaaaaaaaa"; veryVeryLongTitle += "aaaaaaaaaa";
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = veryVeryLongTitle; t.Title = veryVeryLongTitle;
}); });
_routableService.FillSlug(thing.As<RoutableAspect>()); _routableService.FillSlug(thing.As<IsRoutable>());
Assert.That(veryVeryLongTitle.Length, Is.AtLeast(1001)); Assert.That(veryVeryLongTitle.Length, Is.AtLeast(1001));
Assert.That(thing.Slug.Length, Is.EqualTo(1000)); Assert.That(thing.Slug.Length, Is.EqualTo(1000));
@@ -135,11 +136,11 @@ namespace Orchard.Core.Tests.Common.Services {
var contentManager = _container.Resolve<IContentManager>(); var contentManager = _container.Resolve<IContentManager>();
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = "This Is Some Interesting Title"; t.Title = "This Is Some Interesting Title";
}); });
_routableService.FillSlug(thing.As<RoutableAspect>()); _routableService.FillSlug(thing.As<IsRoutable>());
Assert.That(thing.Slug, Is.EqualTo("this-is-some-interesting-title")); Assert.That(thing.Slug, Is.EqualTo("this-is-some-interesting-title"));
} }
@@ -149,12 +150,12 @@ namespace Orchard.Core.Tests.Common.Services {
var contentManager = _container.Resolve<IContentManager>(); var contentManager = _container.Resolve<IContentManager>();
var thing1 = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing1 = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = "This Is Some Interesting Title"; t.Title = "This Is Some Interesting Title";
}); });
var thing2 = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing2 = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = "This Is Some Interesting Title"; t.Title = "This Is Some Interesting Title";
}); });
@@ -166,12 +167,12 @@ namespace Orchard.Core.Tests.Common.Services {
var contentManager = _container.Resolve<IContentManager>(); var contentManager = _container.Resolve<IContentManager>();
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => { var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<RoutableAspect>().Record = new RoutableRecord(); t.As<IsRoutable>().Record = new RoutableRecord();
t.Title = "This Is Some Interesting Title"; t.Title = "This Is Some Interesting Title";
}); });
var stuff = contentManager.Create<Stuff>(StuffDriver.ContentType.Name, s => { var stuff = contentManager.Create<Stuff>(StuffDriver.ContentType.Name, s => {
s.As<RoutableAspect>().Record = new RoutableRecord(); s.As<IsRoutable>().Record = new RoutableRecord();
s.Title = "This Is Some Interesting Title"; s.Title = "This Is Some Interesting Title";
}); });
@@ -198,7 +199,7 @@ namespace Orchard.Core.Tests.Common.Services {
Filters.Add(new ActivatingFilter<Thing>(ThingDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<Thing>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(ThingDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(ThingDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(ThingDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(ThingDriver.ContentType.Name));
} }
} }
@@ -206,13 +207,13 @@ namespace Orchard.Core.Tests.Common.Services {
public int Id { get { return ContentItem.Id; } } public int Id { get { return ContentItem.Id; } }
public string Title { public string Title {
get { return this.As<RoutableAspect>().Title; } get { return this.As<IsRoutable>().Title; }
set { this.As<RoutableAspect>().Title = value; } set { this.As<IsRoutable>().Title = value; }
} }
public string Slug { public string Slug {
get { return this.As<RoutableAspect>().Slug; } get { return this.As<IsRoutable>().Slug; }
set { this.As<RoutableAspect>().Slug = value; } set { this.As<IsRoutable>().Slug = value; }
} }
} }
@@ -229,7 +230,7 @@ namespace Orchard.Core.Tests.Common.Services {
Filters.Add(new ActivatingFilter<Stuff>(StuffDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<Stuff>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(StuffDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(StuffDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(StuffDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(StuffDriver.ContentType.Name));
} }
} }
@@ -237,13 +238,13 @@ namespace Orchard.Core.Tests.Common.Services {
public int Id { get { return ContentItem.Id; } } public int Id { get { return ContentItem.Id; } }
public string Title { public string Title {
get { return this.As<RoutableAspect>().Title; } get { return this.As<IsRoutable>().Title; }
set { this.As<RoutableAspect>().Title = value; } set { this.As<IsRoutable>().Title = value; }
} }
public string Slug { public string Slug {
get { return this.As<RoutableAspect>().Slug; } get { return this.As<IsRoutable>().Slug; }
set { this.As<RoutableAspect>().Slug = value; } set { this.As<IsRoutable>().Slug = value; }
} }
} }

View File

@@ -10,13 +10,13 @@ using NUnit.Framework;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Builders; using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Feeds; using Orchard.Core.Feeds;
using Orchard.Core.Feeds.Controllers; using Orchard.Core.Feeds.Controllers;
using Orchard.Core.Feeds.Models; using Orchard.Core.Feeds.Models;
using Orchard.Core.Feeds.Rss; using Orchard.Core.Feeds.Rss;
using Orchard.Core.Feeds.StandardBuilders; using Orchard.Core.Feeds.StandardBuilders;
using Orchard.Core.Routable.Models;
using Orchard.Mvc.Results; using Orchard.Mvc.Results;
using Orchard.Tests.Modules; using Orchard.Tests.Modules;
using Orchard.Tests.Stubs; using Orchard.Tests.Stubs;
@@ -149,16 +149,16 @@ namespace Orchard.Core.Tests.Feeds.Controllers {
var clock = new StubClock(); var clock = new StubClock();
var hello = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("hello").Build()) var hello = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("hello").Build())
.Weld<CommonAspect>() .Weld<CommonAspect>()
.Weld<RoutableAspect>() .Weld<IsRoutable>()
.Weld<BodyAspect>() .Weld<BodyAspect>()
.Build(); .Build();
hello.As<CommonAspect>().Record = new CommonRecord(); hello.As<CommonAspect>().Record = new CommonRecord();
hello.As<RoutableAspect>().Record = new RoutableRecord(); hello.As<IsRoutable>().Record = new RoutableRecord();
hello.As<BodyAspect>().Record = new BodyRecord(); hello.As<BodyAspect>().Record = new BodyRecord();
hello.As<CommonAspect>().PublishedUtc = clock.UtcNow; hello.As<CommonAspect>().PublishedUtc = clock.UtcNow;
hello.As<RoutableAspect>().Title = "alpha"; hello.As<IsRoutable>().Title = "alpha";
hello.As<RoutableAspect>().Slug = "beta"; hello.As<IsRoutable>().Slug = "beta";
hello.As<BodyAspect>().Text = "gamma"; hello.As<BodyAspect>().Text = "gamma";
var query = new StubQuery(new[] { var query = new StubQuery(new[] {

View File

@@ -1,47 +0,0 @@
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models;
using Orchard.Localization;
namespace Orchard.Core.Common.Controllers {
public class RoutableController : Controller, IUpdateModel {
private readonly IContentManager _contentManager;
public RoutableController(IContentManager contentManager) {
_contentManager = contentManager;
}
[HttpPost]
public ActionResult Slugify(string contentType, int? id, int? containerId) {
const string slug = "";
ContentItem contentItem = null;
if (string.IsNullOrEmpty(contentType))
return Json(slug);
if (id != null)
contentItem = _contentManager.Get((int) id);
if (contentItem == null)
contentItem = _contentManager.New(contentType);
if (containerId != null) {
var containerItem = _contentManager.Get((int)containerId);
contentItem.As<ICommonAspect>().Container = containerItem;
}
_contentManager.UpdateEditorModel(contentItem, this);
return Json(contentItem.As<RoutableAspect>().Slug ?? slug);
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
}
}

View File

@@ -29,14 +29,6 @@ namespace Orchard.Core.Common.DataMigrations {
.Column<DateTime>("PublishedUtc") .Column<DateTime>("PublishedUtc")
.Column<DateTime>("ModifiedUtc") .Column<DateTime>("ModifiedUtc")
); );
//CREATE TABLE Common_RoutableRecord (Id INTEGER not null, Title TEXT, Slug TEXT, Path TEXT, ContentItemRecord_id INTEGER, primary key (Id));
SchemaBuilder.CreateTable("RoutableRecord", table => table
.ContentPartVersionRecord()
.Column<string>("Title", column => column.WithLength(1024))
.Column<string>("Slug")
.Column<string>("Path", column => column.WithLength(2048))
);
return 0010; return 0010;
} }

View File

@@ -6,6 +6,7 @@ using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Common.Settings; using Orchard.Core.Common.Settings;
using Orchard.Core.Common.ViewModels; using Orchard.Core.Common.ViewModels;
using Orchard.Core.Routable.Models;
namespace Orchard.Core.Common.Drivers { namespace Orchard.Core.Common.Drivers {
[UsedImplicitly] [UsedImplicitly]
@@ -88,7 +89,7 @@ namespace Orchard.Core.Common.Drivers {
if (common == null) if (common == null)
return this; return this;
var routable = common.Container.As<RoutableAspect>(); var routable = common.Container.As<IsRoutable>();
if (routable == null) if (routable == null)
return this; return this;
@@ -97,7 +98,7 @@ namespace Orchard.Core.Common.Drivers {
} }
public PathBuilder AddSlug() { public PathBuilder AddSlug() {
var routable = _content.As<RoutableAspect>(); var routable = _content.As<IsRoutable>();
if (routable == null) if (routable == null)
return this; return this;

View File

@@ -1,46 +0,0 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Fields;
using Orchard.Core.Common.ViewModels;
namespace Orchard.Core.Common.Drivers {
[UsedImplicitly]
public class ItemReferenceContentFieldDriver : ContentFieldDriver<ItemReferenceContentField> {
public IOrchardServices Services { get; set; }
private const string TemplateName = "Fields/Common.ItemReferenceContentField";
public ItemReferenceContentFieldDriver(IOrchardServices services) {
Services = services;
}
protected override string Prefix {
get { return "ItemReferenceContentField"; }
}
protected override DriverResult Display(ItemReferenceContentField field, string displayType) {
var model = new ItemReferenceContentFieldDisplayViewModel {
Item = Services.ContentManager.Get(field.ContentItemReference.Id)
};
return ContentFieldTemplate(model, TemplateName, Prefix);
}
protected override DriverResult Editor(ItemReferenceContentField field) {
var model = BuildEditorViewModel(field);
return ContentFieldTemplate(model, TemplateName, Prefix).Location("primary", "6");
}
protected override DriverResult Editor(ItemReferenceContentField field, IUpdateModel updater) {
var model = BuildEditorViewModel(field);
updater.TryUpdateModel(model, Prefix, null, null);
return ContentFieldTemplate(model, TemplateName, Prefix).Location("primary", "6");
}
private ItemReferenceContentFieldEditorViewModel BuildEditorViewModel(ItemReferenceContentField field) {
return new ItemReferenceContentFieldEditorViewModel {
Item = Services.ContentManager.Get(field.ContentItemReference.Id)
};
}
}
}

View File

@@ -1,54 +0,0 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.ViewModels;
using Orchard.Core.Common.Services;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Core.Common.Drivers {
[UsedImplicitly]
public class Routable : ContentPartDriver<RoutableAspect> {
private const string TemplateName = "Parts/Common.Routable";
private readonly IOrchardServices _services;
private readonly IRoutableService _routableService;
public Localizer T { get; set; }
protected override string Prefix {
get { return "Routable"; }
}
public Routable(IOrchardServices services, IRoutableService routableService)
{
_services = services;
_routableService = routableService;
T = NullLocalizer.Instance;
}
protected override DriverResult Editor(RoutableAspect part) {
var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
}
protected override DriverResult Editor(RoutableAspect part, IUpdateModel updater) {
var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
updater.TryUpdateModel(model, Prefix, null, null);
if (!_routableService.IsSlugValid(part.Slug)){
updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead)."));
}
string originalSlug = part.Slug;
if(!_routableService.ProcessSlug(part)) {
_services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
originalSlug, part.Slug, part.ContentItem.ContentType));
}
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
}
}
}

View File

@@ -1,65 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.Services;
using Orchard.Data;
namespace Orchard.Core.Common.Handlers {
[UsedImplicitly]
public class RoutableAspectHandler : ContentHandler {
private readonly IEnumerable<IContentItemDriver> _contentItemDrivers;
public RoutableAspectHandler(IRepository<RoutableRecord> repository, IEnumerable<IContentItemDriver> contentItemDrivers, IRoutableService routableService, UrlHelper urlHelper) {
_contentItemDrivers = contentItemDrivers;
Filters.Add(StorageFilter.For(repository));
OnGetEditorViewModel<RoutableAspect>((context, routable) => {
var currentDriver = GetDriver(context.ContentItem);
var tempContentItem = context.ContentItem.ContentManager.New(context.ContentItem.ContentType);
tempContentItem.As<RoutableAspect>().Slug = "ABCDEFG";
var routeValues = GetRouteValues(currentDriver, tempContentItem);
var url = urlHelper.RouteUrl(routeValues).Replace("/ABCDEFG", "");
if (url.StartsWith("/"))
url = url.Substring(1);
routable.ContentItemBasePath = url;
});
OnCreated<RoutableAspect>((context, ra) => routableService.ProcessSlug(ra));
OnIndexing<RoutableAspect>((context, part) => context.DocumentIndex
.Add("slug", part.Slug).Analyze().Store()
.Add("title", part.Title).Analyze()
);
}
private static RouteValueDictionary GetRouteValues(IContentItemDriver driver, ContentItem contentItem) {
//TODO: (erikpo) Need to rearrange ContentItemDriver so reflection isn't needed here
var driverType = driver.GetType();
var method = driverType.GetMethod("GetDisplayRouteValues");
if (method != null) {
return (RouteValueDictionary)method.Invoke(driver, new object[] {contentItem.Get(driverType.BaseType.GetGenericArguments()[0])});
}
return null;
}
private IContentItemDriver GetDriver(ContentItem contentItem) {
return
_contentItemDrivers
.Where(cid => cid.GetContentTypes().Any(ct => string.Compare(ct.Name, contentItem.ContentType, true) == 0))
//TODO: (erikpo) SingleOrDefault should be called here, but for some reason, the amount of drivers registered is doubled sometimes.
.FirstOrDefault();
}
}
}

View File

@@ -1,18 +0,0 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
namespace Orchard.Core.Common.Models {
public class RoutableAspect : ContentPart<RoutableRecord>, IRoutableAspect {
public string ContentItemBasePath { get; set; }
public string Title {
get { return Record.Title; }
set { Record.Title = value; }
}
public string Slug {
get { return Record.Slug; }
set { Record.Slug = value; }
}
}
}

View File

@@ -1,24 +0,0 @@
jQuery.fn.extend({
slugify: function(options) {
//todo: (heskew) need messaging system
if (!options.target || !options.url)
return;
var args = {
"contentType": options.contentType,
"id": options.id,
"containerId": options.containerId,
__RequestVerificationToken: $("input[name=__RequestVerificationToken]").val()
};
args[$(this).attr("name")] = $(this).val();
jQuery.post(
options.url,
args,
function(data) {
options.target.val(data);
},
"json"
);
}
});

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using Orchard.Core.Common.Models;
namespace Orchard.Core.Common.Services {
public interface IRoutableService : IDependency {
void FillSlug<TModel>(TModel model) where TModel : RoutableAspect;
void FillSlug<TModel>(TModel model, Func<string, string> generateSlug) where TModel : RoutableAspect;
string GenerateUniqueSlug(string slugCandidate, IEnumerable<string> existingSlugs);
/// <summary>
/// Returns any content item of the specified content type with similar slugs
/// </summary>
IEnumerable<RoutableAspect> GetSimilarSlugs(string contentType, string slug);
/// <summary>
/// Validates the given slug
/// </summary>
bool IsSlugValid(string slug);
/// <summary>
/// Defines the slug of a RoutableAspect and validate its unicity
/// </summary>
/// <returns>True if the slug has been created, False if a conflict occured</returns>
bool ProcessSlug(RoutableAspect part);
}
}

View File

@@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Orchard.Core.Common.Models;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Core.Common.Services {
[UsedImplicitly]
public class RoutableService : IRoutableService {
private readonly IContentManager _contentManager;
public RoutableService(IContentManager contentManager) {
_contentManager = contentManager;
}
public void FillSlug<TModel>(TModel model) where TModel : RoutableAspect {
if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title))
return;
var slug = model.Title;
var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s]+");
slug = dissallowed.Replace(slug, "-");
slug = slug.Trim('-');
if (slug.Length > 1000)
slug = slug.Substring(0, 1000);
model.Slug = slug.ToLowerInvariant();
}
public void FillSlug<TModel>(TModel model, Func<string, string> generateSlug) where TModel : RoutableAspect {
if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title))
return;
model.Slug = generateSlug(model.Title).ToLowerInvariant();
}
public string GenerateUniqueSlug(string slugCandidate, IEnumerable<string> existingSlugs) {
if (existingSlugs == null || !existingSlugs.Contains(slugCandidate))
return slugCandidate;
int? version = existingSlugs.Select(s => GetSlugVersion(slugCandidate, s)).OrderBy(i => i).LastOrDefault();
return version != null
? string.Format("{0}-{1}", slugCandidate, version)
: slugCandidate;
}
private static int? GetSlugVersion(string slugCandidate, string slug) {
int v;
string[] slugParts = slug.Split(new []{slugCandidate}, StringSplitOptions.RemoveEmptyEntries);
if (slugParts.Length == 0)
return 2;
return int.TryParse(slugParts[0].TrimStart('-'), out v)
? (int?)++v
: null;
}
public IEnumerable<RoutableAspect> GetSimilarSlugs(string contentType, string slug)
{
return
_contentManager.Query(contentType).Join<RoutableRecord>()
.List()
.Select(i => i.As<RoutableAspect>())
.Where(routable => routable.Slug.StartsWith(slug, StringComparison.OrdinalIgnoreCase)) // todo: for some reason the filter doesn't work within the query, even without StringComparison or StartsWith
.ToArray();
}
public bool IsSlugValid(string slug) {
// see http://tools.ietf.org/html/rfc3987 for prohibited chars
return slug == null || String.IsNullOrEmpty(slug.Trim()) || Regex.IsMatch(slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$");
}
public bool ProcessSlug(RoutableAspect part)
{
FillSlug(part);
if (string.IsNullOrEmpty(part.Slug))
{
return true;
}
var slugsLikeThis = GetSimilarSlugs(part.ContentItem.ContentType, part.Slug);
// If the part is already a valid content item, don't include it in the list
// of slug to consider for conflict detection
if (part.ContentItem.Id != 0)
slugsLikeThis = slugsLikeThis.Where(p => p.ContentItem.Id != part.ContentItem.Id);
//todo: (heskew) need better messages
if (slugsLikeThis.Count() > 0)
{
var originalSlug = part.Slug;
//todo: (heskew) make auto-uniqueness optional
part.Slug = GenerateUniqueSlug(part.Slug, slugsLikeThis.Select(p => p.Slug));
if (originalSlug != part.Slug) {
return false;
}
}
return true;
}
}
}

View File

@@ -1,20 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Orchard.Core.Common.Models;
namespace Orchard.Core.Common.ViewModels {
public class RoutableEditorViewModel {
public string Prefix { get; set; }
public RoutableAspect RoutableAspect { get; set; }
[Required]
public string Title {
get { return RoutableAspect.Record.Title; }
set { RoutableAspect.Record.Title = value; }
}
public string Slug {
get { return RoutableAspect.Record.Slug; }
set { RoutableAspect.Record.Slug = value; }
}
}
}

View File

@@ -1,35 +0,0 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<RoutableEditorViewModel>" %>
<%@ Import Namespace="Orchard.Utility.Extensions"%>
<%@ Import Namespace="Orchard.ContentManagement.Extenstions"%>
<%@ Import Namespace="Orchard.ContentManagement"%>
<%@ Import Namespace="Orchard.ContentManagement.Aspects"%>
<%@ Import Namespace="Orchard.Core.Common.ViewModels"%>
<% Html.RegisterFootScript("jquery.slugify.js"); %>
<fieldset>
<%: Html.LabelFor(m => m.Title) %>
<%: Html.TextBoxFor(m => m.Title, new { @class = "large text" }) %>
</fieldset>
<fieldset class="permalink">
<label class="sub" for="Slug"><%: T("Permalink")%><br /><span><%: Request.ToRootUrlString() %>/<%: Model.RoutableAspect.ContentItemBasePath %></span></label>
<span><%: Html.TextBoxFor(m => m.Slug, new { @class = "text" })%></span>
</fieldset>
<% using (this.Capture("end-of-page-scripts")) { %>
<script type="text/javascript">
$(function(){
//pull slug input from tab order
$("<%=String.Format("input#{0}Slug", !string.IsNullOrEmpty(Model.Prefix) ? Model.Prefix + "_" : "") %>").attr("tabindex",-1);
$("<%=String.Format("input#{0}Title", !string.IsNullOrEmpty(Model.Prefix) ? Model.Prefix + "_" : "") %>").blur(function(){
$(this).slugify({
target:$("<%=String.Format("input#{0}Slug", !string.IsNullOrEmpty(Model.Prefix) ? Model.Prefix + "_" : "") %>"),
url:"<%: Url.Slugify() %>",
contentType:"<%=Model.RoutableAspect.ContentItem.ContentType %>",
id:"<%=Model.RoutableAspect.ContentItem.Id %>"<%
var commonAspect = Model.RoutableAspect.ContentItem.As<ICommonAspect>();
var container = commonAspect != null ? commonAspect.Container : null;
if (container != null) { %>,
containerId:<%=container.ContentItem.Id %><%
} %>
})
})
})</script>
<% } %>

View File

@@ -4,6 +4,7 @@ using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Services;
using Orchard.Core.Contents.ViewModels; using Orchard.Core.Contents.ViewModels;
using Orchard.Data; using Orchard.Data;
using Orchard.Localization; using Orchard.Localization;
@@ -19,18 +20,21 @@ namespace Orchard.Core.Contents.Controllers {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ITransactionManager _transactionManager; private readonly ITransactionManager _transactionManager;
private readonly IContentsService _contentsService;
public AdminController( public AdminController(
IOrchardServices orchardServices, IOrchardServices orchardServices,
INotifier notifier, INotifier notifier,
IContentManager contentManager, IContentManager contentManager,
IContentDefinitionManager contentDefinitionManager, IContentDefinitionManager contentDefinitionManager,
ITransactionManager transactionManager) { ITransactionManager transactionManager,
IContentsService contentsService) {
Services = orchardServices; Services = orchardServices;
_notifier = notifier; _notifier = notifier;
_contentManager = contentManager; _contentManager = contentManager;
_contentDefinitionManager = contentDefinitionManager; _contentDefinitionManager = contentDefinitionManager;
_transactionManager = transactionManager; _transactionManager = transactionManager;
_contentsService = contentsService;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
} }
@@ -106,7 +110,7 @@ namespace Orchard.Core.Contents.Controllers {
[HttpPost] [HttpPost]
public ActionResult Create(CreateItemViewModel model) { public ActionResult Create(CreateItemViewModel model, string command, DateTime? scheduledPublishUtc) {
//todo: need to integrate permissions into generic content management //todo: need to integrate permissions into generic content management
var contentItem = _contentManager.New(model.Id); var contentItem = _contentManager.New(model.Id);
model.Content = _contentManager.UpdateEditorModel(contentItem, this); model.Content = _contentManager.UpdateEditorModel(contentItem, this);
@@ -114,15 +118,26 @@ namespace Orchard.Core.Contents.Controllers {
_contentManager.Create(contentItem, VersionOptions.Draft); _contentManager.Create(contentItem, VersionOptions.Draft);
model.Content = _contentManager.UpdateEditorModel(contentItem, this); model.Content = _contentManager.UpdateEditorModel(contentItem, this);
} }
if (ModelState.IsValid) {
_contentManager.Publish(contentItem);
}
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
_transactionManager.Cancel(); _transactionManager.Cancel();
PrepareEditorViewModel(model.Content); PrepareEditorViewModel(model.Content);
return View("Create", model); return View("Create", model);
} }
switch (command) {
case "PublishNow":
_contentsService.Publish(model.Content.Item);
Services.Notifier.Information(T("{0} has been published", contentItem.TypeDefinition.DisplayName));
break;
case "PublishLater":
_contentsService.Publish(model.Content.Item, scheduledPublishUtc.HasValue ? scheduledPublishUtc.Value : DateTime.MaxValue);
Services.Notifier.Information(T("{0} has been scheduled for publishing", contentItem.TypeDefinition.DisplayName));
break;
default:
Services.Notifier.Information(T("{0} draft has been saved", contentItem.TypeDefinition.DisplayName));
break;
}
_notifier.Information(T("Created content item")); _notifier.Information(T("Created content item"));
return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } }); return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } });
} }
@@ -138,7 +153,7 @@ namespace Orchard.Core.Contents.Controllers {
} }
[HttpPost] [HttpPost]
public ActionResult Edit(EditItemViewModel model) { public ActionResult Edit(EditItemViewModel model, string command, DateTime? scheduledPublishUtc) {
var contentItem = _contentManager.Get(model.Id, VersionOptions.DraftRequired); var contentItem = _contentManager.Get(model.Id, VersionOptions.DraftRequired);
model.Content = _contentManager.UpdateEditorModel(contentItem, this); model.Content = _contentManager.UpdateEditorModel(contentItem, this);
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
@@ -146,13 +161,27 @@ namespace Orchard.Core.Contents.Controllers {
PrepareEditorViewModel(model.Content); PrepareEditorViewModel(model.Content);
return View("Edit", model); return View("Edit", model);
} }
_contentManager.Publish(contentItem);
switch (command) {
case "PublishNow":
_contentsService.Publish(model.Content.Item);
Services.Notifier.Information(T("{0} has been published", contentItem.TypeDefinition.DisplayName));
break;
case "PublishLater":
_contentsService.Publish(model.Content.Item, scheduledPublishUtc.HasValue ? scheduledPublishUtc.Value : DateTime.MaxValue);
Services.Notifier.Information(T("{0} has been scheduled for publishing", contentItem.TypeDefinition.DisplayName));
break;
default:
Services.Notifier.Information(T("{0} draft has been saved", contentItem.TypeDefinition.DisplayName));
break;
}
return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } }); return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } });
} }
[HttpPost, ActionName("Remove")] [HttpPost, ActionName("Remove")]
public ActionResult RemovePOST(int id, string returnUrl) { public ActionResult RemovePOST(int id, string returnUrl) {
var contentItem = _contentManager.Get(id); var contentItem = _contentManager.Get(id, VersionOptions.Latest);
if (contentItem != null) if (contentItem != null)
_contentManager.Remove(contentItem); _contentManager.Remove(contentItem);

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.Tasks.Scheduling;
namespace Orchard.Core.Contents.Services {
public class ContentsService : IContentsService {
private readonly IContentManager _contentManager;
private readonly IPublishingTaskManager _publishingTaskManager;
public ContentsService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager) {
_contentManager = contentManager;
_publishingTaskManager = publishingTaskManager;
}
void IContentsService.Publish(ContentItem contentItem) {
_publishingTaskManager.DeleteTasks(contentItem);
_contentManager.Publish(contentItem);
}
void IContentsService.Publish(ContentItem contentItem, DateTime scheduledPublishUtc) {
_publishingTaskManager.Publish(contentItem, scheduledPublishUtc);
}
}
}

View File

@@ -0,0 +1,9 @@
using System;
using Orchard.ContentManagement;
namespace Orchard.Core.Contents.Services {
public interface IContentsService : IDependency {
void Publish(ContentItem contentItem);
void Publish(ContentItem contentItem, DateTime scheduledPublishUtc);
}
}

View File

@@ -3,20 +3,21 @@ using System.Web.Routing;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
namespace Orchard.Core.Feeds.StandardBuilders { namespace Orchard.Core.Feeds.StandardBuilders {
public class ItemInspector { public class ItemInspector {
private readonly IContent _item; private readonly IContent _item;
private readonly ContentItemMetadata _metadata; private readonly ContentItemMetadata _metadata;
private readonly ICommonAspect _common; private readonly ICommonAspect _common;
private readonly RoutableAspect _routable; private readonly IsRoutable _routable;
private readonly BodyAspect _body; private readonly BodyAspect _body;
public ItemInspector(IContent item, ContentItemMetadata metadata) { public ItemInspector(IContent item, ContentItemMetadata metadata) {
_item = item; _item = item;
_metadata = metadata; _metadata = metadata;
_common = item.Get<ICommonAspect>(); _common = item.Get<ICommonAspect>();
_routable = item.Get<RoutableAspect>(); _routable = item.Get<IsRoutable>();
_body = item.Get<BodyAspect>(); _body = item.Get<BodyAspect>();
} }

View File

@@ -9,6 +9,7 @@ using Orchard.Localization;
using Orchard.Localization.Services; using Orchard.Localization.Services;
using Orchard.Mvc.Results; using Orchard.Mvc.Results;
using Orchard.Mvc.ViewModels; using Orchard.Mvc.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.Core.Localization.Controllers { namespace Orchard.Core.Localization.Controllers {
[ValidateInput(false)] [ValidateInput(false)]
@@ -21,9 +22,11 @@ namespace Orchard.Core.Localization.Controllers {
_contentManager = contentManager; _contentManager = contentManager;
_cultureManager = cultureManager; _cultureManager = cultureManager;
_localizationService = localizationService; _localizationService = localizationService;
T = NullLocalizer.Instance;
Services = orchardServices; Services = orchardServices;
} }
public Localizer T { get; set; }
public IOrchardServices Services { get; set; } public IOrchardServices Services { get; set; }
public ActionResult Translate(int id, string to) { public ActionResult Translate(int id, string to) {
@@ -47,8 +50,8 @@ namespace Orchard.Core.Localization.Controllers {
} }
[HttpPost, ActionName("Translate")] [HttpPost, ActionName("Translate")]
public ActionResult TranslatePOST(int id) { public ActionResult TranslatePOST(int id, string command, DateTime? scheduledPublishUtc) {
var contentItem = _contentManager.Get(id, VersionOptions.DraftRequired); var contentItem = _contentManager.Get(id, VersionOptions.Latest);
if (contentItem == null) if (contentItem == null)
return new NotFoundResult(); return new NotFoundResult();
@@ -59,7 +62,7 @@ namespace Orchard.Core.Localization.Controllers {
ContentItem contentItemTranslation; ContentItem contentItemTranslation;
var existingTranslation = _localizationService.GetLocalizedContentItem(contentItem, viewModel.SelectedCulture); var existingTranslation = _localizationService.GetLocalizedContentItem(contentItem, viewModel.SelectedCulture);
if (existingTranslation != null) { // edit existing if (existingTranslation != null) { // edit existing
contentItemTranslation = existingTranslation.ContentItem; contentItemTranslation = _contentManager.Get(existingTranslation.ContentItem.Id, VersionOptions.DraftRequired);
} }
else { // create else { // create
contentItemTranslation = _contentManager.New(contentItem.ContentType); contentItemTranslation = _contentManager.New(contentItem.ContentType);
@@ -79,7 +82,19 @@ namespace Orchard.Core.Localization.Controllers {
return View(viewModel); return View(viewModel);
} }
_contentManager.Publish(contentItemTranslation); switch (command) {
case "PublishNow":
_localizationService.Publish(contentItemTranslation);
Services.Notifier.Information(T("{0} has been published", contentItem.TypeDefinition.DisplayName));
break;
case "PublishLater":
_localizationService.Publish(contentItemTranslation, scheduledPublishUtc.HasValue ? scheduledPublishUtc.Value : DateTime.MaxValue);
Services.Notifier.Information(T("{0} has been scheduled for publishing", contentItem.TypeDefinition.DisplayName));
break;
default:
Services.Notifier.Information(T("{0} draft has been saved", contentItem.TypeDefinition.DisplayName));
break;
}
var metadata = _contentManager.GetItemMetadata(viewModel.Content.Item); var metadata = _contentManager.GetItemMetadata(viewModel.Content.Item);
if (metadata.EditorRouteValues == null) if (metadata.EditorRouteValues == null)

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Localization.Models; using Orchard.Core.Localization.Models;
@@ -7,5 +8,7 @@ namespace Orchard.Core.Localization.Services {
Localized GetLocalizedContentItem(IContent masterContentItem, string culture); Localized GetLocalizedContentItem(IContent masterContentItem, string culture);
string GetContentCulture(IContent contentItem); string GetContentCulture(IContent contentItem);
IEnumerable<IContent> GetLocalizations(IContent contentItem); IEnumerable<IContent> GetLocalizations(IContent contentItem);
void Publish(ContentItem contentItem);
void Publish(ContentItem contentItem, DateTime scheduledPublishUtc);
} }
} }

View File

@@ -4,15 +4,18 @@ using System.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Localization.Models; using Orchard.Core.Localization.Models;
using Orchard.Localization.Services; using Orchard.Localization.Services;
using Orchard.Tasks.Scheduling;
namespace Orchard.Core.Localization.Services { namespace Orchard.Core.Localization.Services {
public class LocalizationService : ILocalizationService { public class LocalizationService : ILocalizationService {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly ICultureManager _cultureManager; private readonly ICultureManager _cultureManager;
private readonly IPublishingTaskManager _publishingTaskManager;
public LocalizationService(IContentManager contentManager, ICultureManager cultureManager) { public LocalizationService(IContentManager contentManager, ICultureManager cultureManager, IPublishingTaskManager publishingTaskManager) {
_contentManager = contentManager; _contentManager = contentManager;
_cultureManager = cultureManager; _cultureManager = cultureManager;
_publishingTaskManager = publishingTaskManager;
} }
Localized ILocalizationService.GetLocalizedContentItem(IContent content, string culture) { Localized ILocalizationService.GetLocalizedContentItem(IContent content, string culture) {
@@ -43,5 +46,14 @@ namespace Orchard.Core.Localization.Services {
.Select(i => i.As<Localized>()) .Select(i => i.As<Localized>())
.Where(l => l.MasterContentItem != null && l.MasterContentItem.ContentItem.Id == content.ContentItem.Id); .Where(l => l.MasterContentItem != null && l.MasterContentItem.ContentItem.Id == content.ContentItem.Id);
} }
void ILocalizationService.Publish(ContentItem contentItem) {
_publishingTaskManager.DeleteTasks(contentItem);
_contentManager.Publish(contentItem);
}
void ILocalizationService.Publish(ContentItem contentItem, DateTime scheduledPublishUtc) {
_publishingTaskManager.Publish(contentItem, scheduledPublishUtc);
}
} }
} }

View File

@@ -64,11 +64,8 @@
<Compile Include="Common\DataMigrations\CommonDataMigration.cs" /> <Compile Include="Common\DataMigrations\CommonDataMigration.cs" />
<Compile Include="Common\Drivers\BodyDriver.cs" /> <Compile Include="Common\Drivers\BodyDriver.cs" />
<Compile Include="Common\Drivers\CommonDriver.cs" /> <Compile Include="Common\Drivers\CommonDriver.cs" />
<Compile Include="Common\Drivers\RoutableDriver.cs" />
<Compile Include="Common\Controllers\RoutableController.cs" />
<Compile Include="Common\Drivers\TextFieldDriver.cs" /> <Compile Include="Common\Drivers\TextFieldDriver.cs" />
<Compile Include="Common\Fields\TextField.cs" /> <Compile Include="Common\Fields\TextField.cs" />
<Compile Include="Common\Handlers\RoutableAspectHandler.cs" />
<Compile Include="Common\Services\ICommonService.cs" /> <Compile Include="Common\Services\ICommonService.cs" />
<Compile Include="Common\Services\CommonService.cs" /> <Compile Include="Common\Services\CommonService.cs" />
<Compile Include="Common\Settings\BodySettings.cs" /> <Compile Include="Common\Settings\BodySettings.cs" />
@@ -79,6 +76,8 @@
<Compile Include="Contents\Controllers\ItemController.cs" /> <Compile Include="Contents\Controllers\ItemController.cs" />
<Compile Include="Contents\Drivers\ContentsDriver.cs" /> <Compile Include="Contents\Drivers\ContentsDriver.cs" />
<Compile Include="Contents\Handlers\ContentsHandler.cs" /> <Compile Include="Contents\Handlers\ContentsHandler.cs" />
<Compile Include="Contents\Services\IContentsService.cs" />
<Compile Include="Contents\Services\ContentsService.cs" />
<Compile Include="Contents\ViewModels\EditItemViewModel.cs" /> <Compile Include="Contents\ViewModels\EditItemViewModel.cs" />
<Compile Include="Contents\ViewModels\ListContentsViewModel.cs" /> <Compile Include="Contents\ViewModels\ListContentsViewModel.cs" />
<Compile Include="Contents\ViewModels\ListContentTypesViewModel.cs" /> <Compile Include="Contents\ViewModels\ListContentTypesViewModel.cs" />
@@ -97,6 +96,7 @@
<Compile Include="Reports\ViewModels\DisplayReportViewModel.cs" /> <Compile Include="Reports\ViewModels\DisplayReportViewModel.cs" />
<Compile Include="Reports\ViewModels\ReportsAdminIndexViewModel.cs" /> <Compile Include="Reports\ViewModels\ReportsAdminIndexViewModel.cs" />
<Compile Include="Routable\Controllers\ItemController.cs" /> <Compile Include="Routable\Controllers\ItemController.cs" />
<Compile Include="Routable\DataMigrations\RoutableDataMigration.cs" />
<Compile Include="Routable\Drivers\RoutableDriver.cs" /> <Compile Include="Routable\Drivers\RoutableDriver.cs" />
<Compile Include="Routable\Handlers\RoutableHandler.cs" /> <Compile Include="Routable\Handlers\RoutableHandler.cs" />
<Compile Include="Routable\IRoutablePathConstraint.cs" /> <Compile Include="Routable\IRoutablePathConstraint.cs" />
@@ -104,20 +104,15 @@
<Compile Include="Common\Permissions.cs" /> <Compile Include="Common\Permissions.cs" />
<Compile Include="Common\Models\CommonVersionRecord.cs" /> <Compile Include="Common\Models\CommonVersionRecord.cs" />
<Compile Include="Common\Routes.cs" /> <Compile Include="Common\Routes.cs" />
<Compile Include="Common\Services\IRoutableService.cs" />
<Compile Include="Common\Services\RoutableService.cs" />
<Compile Include="Common\Utilities\LazyField.cs" /> <Compile Include="Common\Utilities\LazyField.cs" />
<Compile Include="Common\Handlers\CommonAspectHandler.cs" /> <Compile Include="Common\Handlers\CommonAspectHandler.cs" />
<Compile Include="Common\Models\CommonAspect.cs" /> <Compile Include="Common\Models\CommonAspect.cs" />
<Compile Include="Common\Handlers\BodyAspectHandler.cs" /> <Compile Include="Common\Handlers\BodyAspectHandler.cs" />
<Compile Include="Common\Models\BodyAspect.cs" /> <Compile Include="Common\Models\BodyAspect.cs" />
<Compile Include="Common\Models\RoutableAspect.cs" />
<Compile Include="Common\Models\BodyRecord.cs" /> <Compile Include="Common\Models\BodyRecord.cs" />
<Compile Include="Common\Models\CommonRecord.cs" /> <Compile Include="Common\Models\CommonRecord.cs" />
<Compile Include="Common\Models\RoutableRecord.cs" />
<Compile Include="Common\ViewModels\BodyDisplayViewModel.cs" /> <Compile Include="Common\ViewModels\BodyDisplayViewModel.cs" />
<Compile Include="Common\ViewModels\BodyEditorViewModel.cs" /> <Compile Include="Common\ViewModels\BodyEditorViewModel.cs" />
<Compile Include="Common\ViewModels\RoutableEditorViewModel.cs" />
<Compile Include="Common\ViewModels\OwnerEditorViewModel.cs" /> <Compile Include="Common\ViewModels\OwnerEditorViewModel.cs" />
<Compile Include="Contents\AdminMenu.cs" /> <Compile Include="Contents\AdminMenu.cs" />
<Compile Include="Contents\Controllers\AdminController.cs" /> <Compile Include="Contents\Controllers\AdminController.cs" />
@@ -165,6 +160,7 @@
<Compile Include="Navigation\ViewModels\MenuItemEntry.cs" /> <Compile Include="Navigation\ViewModels\MenuItemEntry.cs" />
<Compile Include="Navigation\ViewModels\NavigationManagementViewModel.cs" /> <Compile Include="Navigation\ViewModels\NavigationManagementViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Routable\Models\RoutableRecord.cs" />
<Compile Include="Routable\Routes.cs" /> <Compile Include="Routable\Routes.cs" />
<Compile Include="Routable\Services\IRoutableService.cs" /> <Compile Include="Routable\Services\IRoutableService.cs" />
<Compile Include="Routable\Services\RoutablePathConstraint.cs" /> <Compile Include="Routable\Services\RoutablePathConstraint.cs" />
@@ -285,9 +281,7 @@
<Content Include="Common\Views\Web.config" /> <Content Include="Common\Views\Web.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Common\Scripts\jquery.slugify.js" />
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Body.ascx" /> <Content Include="Common\Views\DisplayTemplates\Parts\Common.Body.ascx" />
<Content Include="Common\Views\EditorTemplates\Parts\Common.Routable.ascx" />
<Content Include="Common\Views\EditorTemplates\Parts\Common.Body.ascx" /> <Content Include="Common\Views\EditorTemplates\Parts\Common.Body.ascx" />
<Content Include="Common\Views\EditorTemplates\Parts\Common.Owner.ascx" /> <Content Include="Common\Views\EditorTemplates\Parts\Common.Owner.ascx" />
<Content Include="Feeds\Module.txt" /> <Content Include="Feeds\Module.txt" />

View File

@@ -0,0 +1,18 @@
using Orchard.Data.Migration;
namespace Orchard.Core.Routable.DataMigrations {
public class RoutableDataMigration : DataMigrationImpl {
public int Create() {
//CREATE TABLE Routable_RoutableRecord (Id INTEGER not null, Title TEXT, Slug TEXT, Path TEXT, ContentItemRecord_id INTEGER, primary key (Id));
SchemaBuilder.CreateTable("RoutableRecord", table => table
.ContentPartVersionRecord()
.Column<string>("Title", column => column.WithLength(1024))
.Column<string>("Slug")
.Column<string>("Path", column => column.WithLength(2048))
);
return 0010;
}
}
}

View File

@@ -1,8 +1,6 @@
using JetBrains.Annotations; using Orchard.ContentManagement;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models; using Orchard.Core.Routable.Models;
using Orchard.Core.Routable.Services; using Orchard.Core.Routable.Services;
using Orchard.Core.Routable.ViewModels; using Orchard.Core.Routable.ViewModels;

View File

@@ -1,20 +1,11 @@
using System.Web.Routing; using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Routable.Models; using Orchard.Core.Routable.Models;
using Orchard.Data;
namespace Orchard.Core.Routable.Handlers { namespace Orchard.Core.Routable.Handlers {
public class RoutableHandler : ContentHandlerBase { public class RoutableHandler : ContentHandler {
public override void GetContentItemMetadata(GetContentItemMetadataContext context) { public RoutableHandler(IRepository<RoutableRecord> repository) {
var routable = context.ContentItem.As<IsRoutable>(); Filters.Add(StorageFilter.For(repository));
if (routable != null) {
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
{"Area", "Routable"},
{"Controller", "Item"},
{"Action", "Display"},
{"Path", context.ContentItem.As<IsRoutable>().Record.Path}
};
}
} }
} }
} }

View File

@@ -1,6 +1,5 @@
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models;
namespace Orchard.Core.Routable.Models { namespace Orchard.Core.Routable.Models {
public class IsRoutable : ContentPart<RoutableRecord>, IRoutableAspect { public class IsRoutable : ContentPart<RoutableRecord>, IRoutableAspect {
@@ -13,6 +12,5 @@ namespace Orchard.Core.Routable.Models {
get { return Record.Slug; } get { return Record.Slug; }
set { Record.Slug = value; } set { Record.Slug = value; }
} }
} }
} }

View File

@@ -1,8 +1,7 @@
using System; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement.Records; using Orchard.ContentManagement.Records;
namespace Orchard.Core.Common.Models { namespace Orchard.Core.Routable.Models {
public class RoutableRecord : ContentPartVersionRecord { public class RoutableRecord : ContentPartVersionRecord {
[StringLength(1024)] [StringLength(1024)]
public virtual string Title { get; set; } public virtual string Title { get; set; }

View File

@@ -8,4 +8,4 @@ description: The routable module enables content items to be accessed through a
features: features:
Routable: Routable:
Description: Routable content part. Description: Routable content part.
Category: Core2 Category: Core

View File

@@ -1,6 +1,6 @@
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Core.Common.Models; using Orchard.Core.Routable.Models;
using Orchard.Data; using Orchard.Data;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Tasks; using Orchard.Tasks;

View File

@@ -2,15 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models; using Orchard.Core.Routable.Models;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Core.Routable.Services { namespace Orchard.Core.Routable.Services {
[UsedImplicitly]
public class RoutableService : IRoutableService { public class RoutableService : IRoutableService {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;

View File

@@ -2,14 +2,13 @@
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.Blogs.Models;
using Orchard.Commands; using Orchard.Commands;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Navigation.Models; using Orchard.Core.Navigation.Models;
using Orchard.Core.Routable.Models;
using Orchard.Security; using Orchard.Security;
using System.IO;
using Orchard.Blogs.Services; using Orchard.Blogs.Services;
using Orchard.Core.Navigation.Services; using Orchard.Core.Navigation.Services;
@@ -55,8 +54,8 @@ namespace Orchard.Blogs.Commands {
var blog = _contentManager.New("Blog"); var blog = _contentManager.New("Blog");
blog.As<ICommonAspect>().Owner = admin; blog.As<ICommonAspect>().Owner = admin;
blog.As<RoutableAspect>().Slug = Slug; blog.As<IsRoutable>().Slug = Slug;
blog.As<RoutableAspect>().Title = Title; blog.As<IsRoutable>().Title = Title;
if ( !String.IsNullOrWhiteSpace(MenuText) ) { if ( !String.IsNullOrWhiteSpace(MenuText) ) {
blog.As<MenuPart>().OnMainMenu = true; blog.As<MenuPart>().OnMainMenu = true;
blog.As<MenuPart>().MenuPosition = _menuService.Get().Select(menuPart => menuPart.MenuPosition).Max() + 1 + ".0"; blog.As<MenuPart>().MenuPosition = _menuService.Get().Select(menuPart => menuPart.MenuPosition).Max() + 1 + ".0";
@@ -98,8 +97,8 @@ namespace Orchard.Blogs.Commands {
var post = _contentManager.New("BlogPost"); var post = _contentManager.New("BlogPost");
post.As<ICommonAspect>().Owner = admin; post.As<ICommonAspect>().Owner = admin;
post.As<ICommonAspect>().Container = blog; post.As<ICommonAspect>().Container = blog;
post.As<RoutableAspect>().Slug = Slugify(postName); post.As<IsRoutable>().Slug = Slugify(postName);
post.As<RoutableAspect>().Title = postName; post.As<IsRoutable>().Title = postName;
post.As<BodyAspect>().Text = item.Element("description").Value; post.As<BodyAspect>().Text = item.Element("description").Value;
_contentManager.Create(post); _contentManager.Create(post);
} }

View File

@@ -1,18 +1,13 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Routing; using System.Web.Routing;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Blogs.Models; using Orchard.Blogs.Models;
using Orchard.Blogs.Services; using Orchard.Blogs.Services;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.Services;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Mvc.ViewModels; using Orchard.Mvc.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Drivers { namespace Orchard.Blogs.Drivers {
[UsedImplicitly] [UsedImplicitly]

View File

@@ -5,7 +5,7 @@ using Orchard.Blogs.Models;
using Orchard.Blogs.Services; using Orchard.Blogs.Services;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Services; using Orchard.Core.Routable.Services;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.Blogs.Drivers { namespace Orchard.Blogs.Drivers {

View File

@@ -3,6 +3,7 @@ using Orchard.Blogs.Drivers;
using Orchard.Blogs.Models; using Orchard.Blogs.Models;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
using Orchard.Data; using Orchard.Data;
namespace Orchard.Blogs.Handlers { namespace Orchard.Blogs.Handlers {
@@ -11,7 +12,7 @@ namespace Orchard.Blogs.Handlers {
public BlogHandler(IRepository<BlogRecord> repository) { public BlogHandler(IRepository<BlogRecord> repository) {
Filters.Add(new ActivatingFilter<Blog>(BlogDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<Blog>(BlogDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(BlogDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(BlogDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(BlogDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(BlogDriver.ContentType.Name));
Filters.Add(StorageFilter.For(repository)); Filters.Add(StorageFilter.For(repository));
} }
} }

View File

@@ -8,6 +8,7 @@ using Orchard.Blogs.Services;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Core.Routable.Models;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.Blogs.Handlers { namespace Orchard.Blogs.Handlers {
@@ -24,7 +25,7 @@ namespace Orchard.Blogs.Handlers {
Filters.Add(new ActivatingFilter<BlogPost>(BlogPostDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<BlogPost>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(BlogPostDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(BlogPostDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(BlogPostDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<BodyAspect>(BlogPostDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<BodyAspect>(BlogPostDriver.ContentType.Name));
OnLoaded<BlogPost>((context, p) => p.ScheduledPublishUtc = _blogPostService.GetScheduledPublishUtc(p)); OnLoaded<BlogPost>((context, p) => p.ScheduledPublishUtc = _blogPostService.GetScheduledPublishUtc(p));

View File

@@ -1,6 +1,6 @@
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.Core.Common.Models;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Routable.Models;
namespace Orchard.Blogs.Models { namespace Orchard.Blogs.Models {
public class Blog : ContentPart<BlogRecord> { public class Blog : ContentPart<BlogRecord> {
@@ -8,14 +8,14 @@ namespace Orchard.Blogs.Models {
public int Id { get { return ContentItem.Id; } } public int Id { get { return ContentItem.Id; } }
public string Name { public string Name {
get { return this.As<RoutableAspect>().Title; } get { return this.As<IsRoutable>().Title; }
set { this.As<RoutableAspect>().Title = value; } set { this.As<IsRoutable>().Title = value; }
} }
//TODO: (erikpo) Need a data type for slug //TODO: (erikpo) Need a data type for slug
public string Slug { public string Slug {
get { return this.As<RoutableAspect>().Slug; } get { return this.As<IsRoutable>().Slug; }
set { this.As<RoutableAspect>().Slug = value; } set { this.As<IsRoutable>().Slug = value; }
} }
public string Description { public string Description {

View File

@@ -3,6 +3,7 @@ using System.Web.Mvc;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
using Orchard.Security; using Orchard.Security;
namespace Orchard.Blogs.Models { namespace Orchard.Blogs.Models {
@@ -13,13 +14,13 @@ namespace Orchard.Blogs.Models {
} }
public string Title { public string Title {
get { return this.As<RoutableAspect>().Title; } get { return this.As<IsRoutable>().Title; }
set { this.As<RoutableAspect>().Title = value; } set { this.As<IsRoutable>().Title = value; }
} }
public string Slug { public string Slug {
get { return this.As<RoutableAspect>().Slug; } get { return this.As<IsRoutable>().Slug; }
set { this.As<RoutableAspect>().Slug = value; } set { this.As<IsRoutable>().Slug = value; }
} }
public string Text { public string Text {

View File

@@ -6,6 +6,7 @@ using Orchard.Blogs.Drivers;
using Orchard.Blogs.Models; using Orchard.Blogs.Models;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Routable.Models;
using Orchard.Data; using Orchard.Data;
using Orchard.Tasks.Scheduling; using Orchard.Tasks.Scheduling;

View File

@@ -5,6 +5,7 @@ using Orchard.Blogs.Models;
using Orchard.Blogs.Routing; using Orchard.Blogs.Routing;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Routable.Models;
namespace Orchard.Blogs.Services { namespace Orchard.Blogs.Services {
[UsedImplicitly] [UsedImplicitly]

View File

@@ -2,9 +2,7 @@
<%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%> <%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><a href="<%: Url.BlogForAdmin(Model.Item.Slug) %>"><%: Html.TitleForPage(Model.Item.Name) %></a> <h1><a href="<%: Url.BlogForAdmin(Model.Item.Slug) %>"><%: Html.TitleForPage(Model.Item.Name) %></a></h1>
</h1>
<% Html.Zone("manage"); %><%-- <% Html.Zone("manage"); %><%--
<form> <form>
<div class="actions bulk"> <div class="actions bulk">

View File

@@ -3,6 +3,7 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Navigation.Models; using Orchard.Core.Navigation.Models;
using Orchard.Core.Routable.Models;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Security; using Orchard.Security;
@@ -26,8 +27,8 @@ namespace Orchard.DevTools.Commands {
var pageName = "page" + index; var pageName = "page" + index;
var page = _contentManager.Create("Page", VersionOptions.Draft); var page = _contentManager.Create("Page", VersionOptions.Draft);
page.As<ICommonAspect>().Owner = admin; page.As<ICommonAspect>().Owner = admin;
page.As<RoutableAspect>().Slug = pageName; page.As<IsRoutable>().Slug = pageName;
page.As<RoutableAspect>().Title = pageName; page.As<IsRoutable>().Title = pageName;
page.As<BodyAspect>().Text = pageName; page.As<BodyAspect>().Text = pageName;
page.As<MenuPart>().OnMainMenu = true; page.As<MenuPart>().OnMainMenu = true;
page.As<MenuPart>().MenuPosition = "5." + index; page.As<MenuPart>().MenuPosition = "5." + index;
@@ -37,8 +38,8 @@ namespace Orchard.DevTools.Commands {
var blogName = "blog" + index; var blogName = "blog" + index;
var blog = _contentManager.New("Blog"); var blog = _contentManager.New("Blog");
blog.As<ICommonAspect>().Owner = admin; blog.As<ICommonAspect>().Owner = admin;
blog.As<RoutableAspect>().Slug = blogName; blog.As<IsRoutable>().Slug = blogName;
blog.As<RoutableAspect>().Title = blogName; blog.As<IsRoutable>().Title = blogName;
blog.As<MenuPart>().OnMainMenu = true; blog.As<MenuPart>().OnMainMenu = true;
blog.As<MenuPart>().MenuPosition = "6." + index; blog.As<MenuPart>().MenuPosition = "6." + index;
blog.As<MenuPart>().MenuText = blogName; blog.As<MenuPart>().MenuText = blogName;

View File

@@ -1,5 +1,6 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Core.Routable.Models;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@@ -19,7 +20,7 @@ namespace Orchard.Pages.Handlers {
Filters.Add(new ActivatingFilter<Page>(PageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<Page>(PageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(PageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(PageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(PageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(PageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(PageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(PageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<BodyAspect>(PageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<BodyAspect>(PageDriver.ContentType.Name));
OnLoaded<Page>((context, page) => page._scheduledPublishUtc.Loader(value => _pageService.GetScheduledPublishUtc(page))); OnLoaded<Page>((context, page) => page._scheduledPublishUtc.Loader(value => _pageService.GetScheduledPublishUtc(page)));

View File

@@ -3,6 +3,7 @@ using System.Web.Mvc;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Utilities; using Orchard.ContentManagement.Utilities;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
using Orchard.Security; using Orchard.Security;
namespace Orchard.Pages.Models { namespace Orchard.Pages.Models {
@@ -11,12 +12,12 @@ namespace Orchard.Pages.Models {
public int Id { get { return ContentItem.Id; } } public int Id { get { return ContentItem.Id; } }
public string Title { public string Title {
get { return this.As<RoutableAspect>().Title; } get { return this.As<IsRoutable>().Title; }
} }
public string Slug { public string Slug {
get { return this.As<RoutableAspect>().Slug; } get { return this.As<IsRoutable>().Slug; }
set { this.As<RoutableAspect>().Slug = value; } set { this.As<IsRoutable>().Slug = value; }
} }
public IUser Creator { public IUser Creator {

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.ContentManagement.Records; using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Models; using Orchard.Core.Routable.Models;
using Orchard.Pages.Drivers; using Orchard.Pages.Drivers;
using Orchard.Pages.Models; using Orchard.Pages.Models;
using Orchard.ContentManagement; using Orchard.ContentManagement;

View File

@@ -1,5 +1,6 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
using Orchard.Data; using Orchard.Data;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@@ -13,7 +14,7 @@ namespace Orchard.Sandbox.Handlers {
// define the "SandboxPage" content type // define the "SandboxPage" content type
Filters.Add(new ActivatingFilter<SandboxPage>(SandboxPageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<SandboxPage>(SandboxPageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(SandboxPageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<CommonAspect>(SandboxPageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(SandboxPageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<IsRoutable>(SandboxPageDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<BodyAspect>(SandboxPageDriver.ContentType.Name)); Filters.Add(new ActivatingFilter<BodyAspect>(SandboxPageDriver.ContentType.Name));
Filters.Add(StorageFilter.For(pageRepository) ); Filters.Add(StorageFilter.For(pageRepository) );

View File

@@ -7,11 +7,10 @@ using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models; using Orchard.Core.Common.Models;
using Orchard.Core.Common.Settings; using Orchard.Core.Common.Settings;
using Orchard.Core.Navigation.Models; using Orchard.Core.Navigation.Models;
using Orchard.Core.Routable.Models;
using Orchard.Core.Settings.Models; using Orchard.Core.Settings.Models;
using Orchard.Data; using Orchard.Data;
using Orchard.Data.Migration.Generator;
using Orchard.Data.Migration.Interpreters; using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Providers;
using Orchard.Data.Migration.Schema; using Orchard.Data.Migration.Schema;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
@@ -76,6 +75,7 @@ namespace Orchard.Setup.Services {
"Scheduling", "Scheduling",
"Indexing", "Indexing",
"Localization", "Localization",
"Routable",
"Settings", "Settings",
"XmlRpc", "XmlRpc",
"Orchard.Users", "Orchard.Users",
@@ -186,8 +186,8 @@ namespace Orchard.Setup.Services {
// create home page as a CMS page // create home page as a CMS page
var page = contentManager.Create("Page", VersionOptions.Draft); var page = contentManager.Create("Page", VersionOptions.Draft);
page.As<BodyAspect>().Text = "<p>Welcome to Orchard!</p><p>Congratulations, you've successfully set-up your Orchard site.</p><p>This is the home page of your new site. We've taken the liberty to write here about a few things you could look at next in order to get familiar with the application. Once you feel confident you don't need this anymore, just click <a href=\"Admin/Pages/Edit/3\">Edit</a> to go into edit mode and replace this with whatever you want on your home page to make it your own.</p><p>One thing you could do (but you don't have to) is go into <a href=\"Admin/Settings\">Manage Settings</a> (follow the <a href=\"Admin\">Admin</a> link and then look for it under \"Settings\" in the menu on the left) and check that everything is configured the way you want.</p><p>You probably want to make the site your own. One of the ways you can do that is by clicking <a href=\"Admin/Themes\">Manage Themes</a> in the admin menu. A theme is a packaged look and feel that affects the whole site.</p><p>Next, you can start playing with the content types that we installed. For example, go ahead and click <a href=\"Admin/Pages/Create\">Add New Page</a> in the admin menu and create an \"about\" page. Then, add it to the navigation menu by going to <a href=\"Admin/Navigation\">Manage Menu</a>. You can also click <a href=\"Admin/Blogs/Create\">Add New Blog</a> and start posting by clicking \"Add New Post\".</p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. You can install new themes by going to <a href=\"Admin/Themes\">Manage Themes</a> and clicking <a href=\"Admin/Themes/Install\">Install a new Theme</a>. Like for themes, modules are created by other users of Orchard just like you so if you feel up to it, please <a href=\"http://www.orchardproject.net/\">consider participating</a>.</p><p>--The Orchard Crew</p>"; page.As<BodyAspect>().Text = "<p>Welcome to Orchard!</p><p>Congratulations, you've successfully set-up your Orchard site.</p><p>This is the home page of your new site. We've taken the liberty to write here about a few things you could look at next in order to get familiar with the application. Once you feel confident you don't need this anymore, just click <a href=\"Admin/Pages/Edit/3\">Edit</a> to go into edit mode and replace this with whatever you want on your home page to make it your own.</p><p>One thing you could do (but you don't have to) is go into <a href=\"Admin/Settings\">Manage Settings</a> (follow the <a href=\"Admin\">Admin</a> link and then look for it under \"Settings\" in the menu on the left) and check that everything is configured the way you want.</p><p>You probably want to make the site your own. One of the ways you can do that is by clicking <a href=\"Admin/Themes\">Manage Themes</a> in the admin menu. A theme is a packaged look and feel that affects the whole site.</p><p>Next, you can start playing with the content types that we installed. For example, go ahead and click <a href=\"Admin/Pages/Create\">Add New Page</a> in the admin menu and create an \"about\" page. Then, add it to the navigation menu by going to <a href=\"Admin/Navigation\">Manage Menu</a>. You can also click <a href=\"Admin/Blogs/Create\">Add New Blog</a> and start posting by clicking \"Add New Post\".</p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. You can install new themes by going to <a href=\"Admin/Themes\">Manage Themes</a> and clicking <a href=\"Admin/Themes/Install\">Install a new Theme</a>. Like for themes, modules are created by other users of Orchard just like you so if you feel up to it, please <a href=\"http://www.orchardproject.net/\">consider participating</a>.</p><p>--The Orchard Crew</p>";
page.As<RoutableAspect>().Slug = "home"; page.As<IsRoutable>().Slug = "home";
page.As<RoutableAspect>().Title = T("Home").ToString(); page.As<IsRoutable>().Title = T("Home").ToString();
page.As<CommonAspect>().Owner = user; page.As<CommonAspect>().Owner = user;
if (page.Has<HasComments>()) { if (page.Has<HasComments>()) {
page.As<HasComments>().CommentsShown = false; page.As<HasComments>().CommentsShown = false;