mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Groundwork for rss support by container id
--HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045452
This commit is contained in:
@@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Autofac.Builder;
|
||||||
|
using Autofac.Modules;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Handlers;
|
||||||
|
using Orchard.Core.Common.Models;
|
||||||
|
using Orchard.Core.Common.Records;
|
||||||
|
using Orchard.Core.Feeds;
|
||||||
|
using Orchard.Core.Feeds.Controllers;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
using Orchard.Core.Feeds.Rss;
|
||||||
|
using Orchard.Core.Feeds.Services;
|
||||||
|
using Orchard.Mvc.Results;
|
||||||
|
using Orchard.Tests.Packages;
|
||||||
|
using Orchard.Tests.Stubs;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Tests.Feeds.Controllers {
|
||||||
|
[TestFixture]
|
||||||
|
public class FeedControllerTests {
|
||||||
|
[Test]
|
||||||
|
public void InvalidFormatShpuldReturnNotFoundResult() {
|
||||||
|
var controller = new FeedController(
|
||||||
|
Enumerable.Empty<IFeedQueryProvider>(),
|
||||||
|
Enumerable.Empty<IFeedFormatterProvider>(),
|
||||||
|
Enumerable.Empty<IFeedItemBuilder>()) {
|
||||||
|
ValueProvider = Values.From(new { })
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = controller.Index("no-such-format");
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result, Is.TypeOf<NotFoundResult>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ControllerShouldReturnAnActionResult() {
|
||||||
|
var formatProvider = new Mock<IFeedFormatterProvider>();
|
||||||
|
var format = new Mock<IFeedFormatter>();
|
||||||
|
formatProvider.Setup(x => x.Match(It.IsAny<FeedContext>()))
|
||||||
|
.Returns(new FeedFormatterMatch { FeedFormatter = format.Object, Priority = 10 });
|
||||||
|
|
||||||
|
var queryProvider = new Mock<IFeedQueryProvider>();
|
||||||
|
var query = new Mock<IFeedQuery>();
|
||||||
|
queryProvider.Setup(x => x.Match(It.IsAny<FeedContext>()))
|
||||||
|
.Returns(new FeedQueryMatch { FeedQuery = query.Object, Priority = 10 });
|
||||||
|
|
||||||
|
|
||||||
|
format.Setup(x => x.Process(It.IsAny<FeedContext>(), It.IsAny<Action>())).Returns(new ContentResult());
|
||||||
|
|
||||||
|
var controller = new FeedController(
|
||||||
|
new[] { queryProvider.Object },
|
||||||
|
new[] { formatProvider.Object },
|
||||||
|
Enumerable.Empty<IFeedItemBuilder>()) {
|
||||||
|
ValueProvider = Values.From(new { })
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = controller.Index("test-format");
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result, Is.InstanceOf<ActionResult>());
|
||||||
|
|
||||||
|
formatProvider.Verify();
|
||||||
|
queryProvider.Verify();
|
||||||
|
format.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class StubQuery : IFeedQueryProvider, IFeedQuery {
|
||||||
|
private readonly IEnumerable<ContentItem> _items;
|
||||||
|
|
||||||
|
public StubQuery(IEnumerable<ContentItem> items) {
|
||||||
|
_items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedQueryMatch Match(FeedContext context) {
|
||||||
|
return new FeedQueryMatch { FeedQuery = this, Priority = 10 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(FeedContext context) {
|
||||||
|
foreach (var item in _items) {
|
||||||
|
context.FeedFormatter.AddItem(context, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RssFeedShouldBeStructuredAppropriately() {
|
||||||
|
var query = new StubQuery(Enumerable.Empty<ContentItem>());
|
||||||
|
|
||||||
|
var builder = new ContainerBuilder();
|
||||||
|
builder.RegisterModule(new ImplicitCollectionSupportModule());
|
||||||
|
builder.Register<FeedController>();
|
||||||
|
builder.Register<RssFeedFormatProvider>().As<IFeedFormatterProvider>();
|
||||||
|
builder.Register(query).As<IFeedQueryProvider>();
|
||||||
|
var container = builder.Build();
|
||||||
|
|
||||||
|
var controller = container.Resolve<FeedController>();
|
||||||
|
controller.ValueProvider = Values.From(new { });
|
||||||
|
|
||||||
|
var result = controller.Index("rss");
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result, Is.InstanceOf<RssResult>());
|
||||||
|
|
||||||
|
var doc = ((RssResult)result).Document;
|
||||||
|
Assert.That(doc.Root.Name, Is.EqualTo(XName.Get("rss")));
|
||||||
|
Assert.That(doc.Root.Elements().Single().Name, Is.EqualTo(XName.Get("channel")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OneItemPerContentItemShouldBeCreated() {
|
||||||
|
var query = new StubQuery(new[] {
|
||||||
|
new ContentItem(),
|
||||||
|
new ContentItem(),
|
||||||
|
});
|
||||||
|
|
||||||
|
var builder = new ContainerBuilder();
|
||||||
|
builder.RegisterModule(new ImplicitCollectionSupportModule());
|
||||||
|
builder.Register<FeedController>();
|
||||||
|
builder.Register<RssFeedFormatProvider>().As<IFeedFormatterProvider>();
|
||||||
|
builder.Register(query).As<IFeedQueryProvider>();
|
||||||
|
var container = builder.Build();
|
||||||
|
|
||||||
|
var controller = container.Resolve<FeedController>();
|
||||||
|
controller.ValueProvider = Values.From(new { });
|
||||||
|
|
||||||
|
var result = controller.Index("rss");
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result, Is.InstanceOf<RssResult>());
|
||||||
|
|
||||||
|
var doc = ((RssResult)result).Document;
|
||||||
|
var items = doc.Elements("rss").Elements("channel").Elements("item");
|
||||||
|
Assert.That(items.Count(), Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CorePartValuesAreExtracted() {
|
||||||
|
var clock = new StubClock();
|
||||||
|
var hello = new ContentItemBuilder("hello")
|
||||||
|
.Weld<CommonAspect>()
|
||||||
|
.Weld<RoutableAspect>()
|
||||||
|
.Weld<BodyAspect>()
|
||||||
|
.Build();
|
||||||
|
hello.As<CommonAspect>().Record = new CommonRecord();
|
||||||
|
hello.As<RoutableAspect>().Record = new RoutableRecord();
|
||||||
|
hello.As<BodyAspect>().Record = new BodyRecord();
|
||||||
|
|
||||||
|
hello.As<CommonAspect>().PublishedUtc = clock.UtcNow;
|
||||||
|
hello.As<RoutableAspect>().Title = "alpha";
|
||||||
|
hello.As<RoutableAspect>().Slug = "beta";
|
||||||
|
hello.As<BodyAspect>().Text = "gamma";
|
||||||
|
|
||||||
|
var query = new StubQuery(new[] {
|
||||||
|
hello,
|
||||||
|
});
|
||||||
|
|
||||||
|
var mockContentManager = new Mock<IContentManager>();
|
||||||
|
mockContentManager.Setup(x => x.GetItemMetadata(It.IsAny<IContent>()))
|
||||||
|
.Returns(new ContentItemMetadata { DisplayText = "foo" });
|
||||||
|
|
||||||
|
var builder = new ContainerBuilder();
|
||||||
|
builder.RegisterModule(new ImplicitCollectionSupportModule());
|
||||||
|
builder.Register<FeedController>();
|
||||||
|
builder.Register(mockContentManager.Object).As<IContentManager>();
|
||||||
|
builder.Register<RssFeedFormatProvider>().As<IFeedFormatterProvider>();
|
||||||
|
builder.Register<CorePartsFeedItemBuilder>().As<IFeedItemBuilder>();
|
||||||
|
builder.Register(query).As<IFeedQueryProvider>();
|
||||||
|
var container = builder.Build();
|
||||||
|
|
||||||
|
var controller = container.Resolve<FeedController>();
|
||||||
|
controller.ValueProvider = Values.From(new { });
|
||||||
|
|
||||||
|
var result = controller.Index("rss");
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result, Is.InstanceOf<RssResult>());
|
||||||
|
|
||||||
|
var doc = ((RssResult)result).Document;
|
||||||
|
var item = doc.Elements("rss").Elements("channel").Elements("item").Single();
|
||||||
|
Assert.That(item.Element("title").Value, Is.EqualTo("foo"));
|
||||||
|
Assert.That(item.Element("description").Value, Is.EqualTo("gamma"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -60,6 +60,10 @@
|
|||||||
<HintPath>..\..\lib\sqlite\System.Data.SQLite.DLL</HintPath>
|
<HintPath>..\..\lib\sqlite\System.Data.SQLite.DLL</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System.Xml.Linq">
|
<Reference Include="System.Xml.Linq">
|
||||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -71,6 +75,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Common\Providers\CommonAspectProviderTests.cs" />
|
<Compile Include="Common\Providers\CommonAspectProviderTests.cs" />
|
||||||
|
<Compile Include="Feeds\Controllers\FeedControllerTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Scheduling\ScheduledTaskManagerTests.cs" />
|
<Compile Include="Scheduling\ScheduledTaskManagerTests.cs" />
|
||||||
<Compile Include="Scheduling\ScheduledTaskExecutorTests.cs" />
|
<Compile Include="Scheduling\ScheduledTaskExecutorTests.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
using Orchard.Logging;
|
||||||
|
using Orchard.Mvc.Results;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Controllers {
|
||||||
|
|
||||||
|
public class FeedController : Controller {
|
||||||
|
private readonly IEnumerable<IFeedFormatterProvider> _feedFormatProviders;
|
||||||
|
private readonly IEnumerable<IFeedQueryProvider> _feedQueryProviders;
|
||||||
|
private readonly IEnumerable<IFeedItemBuilder> _feedItemBuilders;
|
||||||
|
|
||||||
|
public FeedController(
|
||||||
|
IEnumerable<IFeedQueryProvider> feedQueryProviders,
|
||||||
|
IEnumerable<IFeedFormatterProvider> feedFormatProviders,
|
||||||
|
IEnumerable<IFeedItemBuilder> feedItemBuilders) {
|
||||||
|
_feedQueryProviders = feedQueryProviders;
|
||||||
|
_feedFormatProviders = feedFormatProviders;
|
||||||
|
_feedItemBuilders = feedItemBuilders;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
public ActionResult Index(string format) {
|
||||||
|
var context = new FeedContext(ValueProvider, format);
|
||||||
|
|
||||||
|
var bestFormatterMatch = _feedFormatProviders
|
||||||
|
.Select(provider => provider.Match(context))
|
||||||
|
.Where(match => match != null && match.FeedFormatter != null)
|
||||||
|
.OrderByDescending(match => match.Priority)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (bestFormatterMatch == null || bestFormatterMatch.FeedFormatter == null)
|
||||||
|
return new NotFoundResult();
|
||||||
|
|
||||||
|
context.FeedFormatter = bestFormatterMatch.FeedFormatter;
|
||||||
|
|
||||||
|
var bestQueryMatch = _feedQueryProviders
|
||||||
|
.Select(provider => provider.Match(context))
|
||||||
|
.Where(match => match != null && match.FeedQuery != null)
|
||||||
|
.OrderByDescending(match => match.Priority)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (bestQueryMatch == null || bestQueryMatch.FeedQuery == null)
|
||||||
|
return new NotFoundResult();
|
||||||
|
|
||||||
|
return context.FeedFormatter.Process(context, () => {
|
||||||
|
bestQueryMatch.FeedQuery.Execute(context);
|
||||||
|
_feedItemBuilders.Invoke(x => x.Populate(context), Logger);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds {
|
||||||
|
public interface IFeedFormatter {
|
||||||
|
ActionResult Process(FeedContext context, Action populate);
|
||||||
|
|
||||||
|
FeedItem AddItem(FeedContext context, ContentItem contentItem);
|
||||||
|
void AddProperty(FeedContext context, FeedItem feedItem, string name, string value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds {
|
||||||
|
public interface IFeedFormatterProvider : IDependency {
|
||||||
|
FeedFormatterMatch Match(FeedContext context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FeedFormatterMatch {
|
||||||
|
public int Priority { get; set; }
|
||||||
|
public IFeedFormatter FeedFormatter { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds {
|
||||||
|
public interface IFeedItemBuilder : IEvents {
|
||||||
|
void Populate(FeedContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds {
|
||||||
|
public interface IFeedQuery {
|
||||||
|
void Execute(FeedContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds {
|
||||||
|
public interface IFeedQueryProvider : IEvents {
|
||||||
|
FeedQueryMatch Match(FeedContext context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FeedQueryMatch {
|
||||||
|
public int Priority { get; set; }
|
||||||
|
public IFeedQuery FeedQuery { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Models {
|
||||||
|
public class FeedContext {
|
||||||
|
public FeedContext(IValueProvider valueProvider, string format) {
|
||||||
|
ValueProvider = valueProvider;
|
||||||
|
Format = format;
|
||||||
|
Response = new FeedResponse();
|
||||||
|
FeedData = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IValueProvider ValueProvider { get; set; }
|
||||||
|
public string Format { get; set; }
|
||||||
|
|
||||||
|
public IFeedFormatter FeedFormatter { get; set; }
|
||||||
|
|
||||||
|
public IDictionary<string, object> FeedData { get; set; }
|
||||||
|
|
||||||
|
public FeedResponse Response { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Xml.Linq;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Models {
|
||||||
|
public class FeedItem {
|
||||||
|
public ContentItem ContentItem { get; set; }
|
||||||
|
public XElement Element { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Models {
|
||||||
|
public class FeedResponse {
|
||||||
|
public FeedResponse() {
|
||||||
|
Items = new List<FeedItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<FeedItem> Items { get; set; }
|
||||||
|
public XElement Element { get; set; }
|
||||||
|
public ActionResult Result { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
name: Feeds
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Web.Routing;
|
||||||
|
using Orchard.Mvc.Routes;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Rss {
|
||||||
|
public class Routes : IRouteProvider {
|
||||||
|
public IEnumerable<RouteDescriptor> GetRoutes() {
|
||||||
|
return new[] {
|
||||||
|
new RouteDescriptor {Priority =-10,
|
||||||
|
Route = new Route(
|
||||||
|
"rss",
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Feeds"},
|
||||||
|
{"controller", "Feed"},
|
||||||
|
{"action", "Index"},
|
||||||
|
{"format", "rss"},
|
||||||
|
},
|
||||||
|
new RouteValueDictionary(),
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Feeds"}
|
||||||
|
},
|
||||||
|
new MvcRouteHandler())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||||
|
foreach (RouteDescriptor routeDescriptor in GetRoutes()) {
|
||||||
|
routes.Add(routeDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Rss {
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class RssFeedFormatProvider : IFeedFormatterProvider, IFeedFormatter {
|
||||||
|
public FeedFormatterMatch Match(FeedContext context) {
|
||||||
|
if (context.Format == "rss") {
|
||||||
|
return new FeedFormatterMatch {
|
||||||
|
FeedFormatter = this,
|
||||||
|
Priority = -5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult Process(FeedContext context, Action populate) {
|
||||||
|
var rss = new XElement("rss");
|
||||||
|
rss.SetAttributeValue("version", "2.0");
|
||||||
|
|
||||||
|
var channel = new XElement("channel");
|
||||||
|
context.Response.Element = channel;
|
||||||
|
rss.Add(channel);
|
||||||
|
|
||||||
|
populate();
|
||||||
|
|
||||||
|
return new RssResult(new XDocument(rss));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedItem AddItem(FeedContext context, ContentItem contentItem) {
|
||||||
|
var feedItem = new FeedItem {
|
||||||
|
ContentItem = contentItem,
|
||||||
|
Element = new XElement("item"),
|
||||||
|
};
|
||||||
|
context.Response.Items.Add(feedItem);
|
||||||
|
context.Response.Element.Add(feedItem.Element);
|
||||||
|
return feedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddProperty(FeedContext context, FeedItem feedItem, string name, string value) {
|
||||||
|
if (feedItem == null) {
|
||||||
|
context.Response.Element.Add(new XElement(name, value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
feedItem.Element.Add(new XElement(name, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Rss {
|
||||||
|
public class RssResult : ActionResult {
|
||||||
|
public XDocument Document { get; private set; }
|
||||||
|
|
||||||
|
public RssResult(XDocument document) {
|
||||||
|
Document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExecuteResult(ControllerContext context) {
|
||||||
|
|
||||||
|
// not returning application/rss+xml because of
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=256379
|
||||||
|
context.HttpContext.Response.ContentType = "text/xml";
|
||||||
|
|
||||||
|
using (var writer = XmlWriter.Create(context.HttpContext.Response.Output))
|
||||||
|
Document.WriteTo(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Aspects;
|
||||||
|
using Orchard.Core.Common.Models;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.Services {
|
||||||
|
public class CorePartsFeedItemBuilder : IFeedItemBuilder {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
|
||||||
|
public CorePartsFeedItemBuilder(IContentManager contentManager) {
|
||||||
|
_contentManager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Populate(FeedContext context) {
|
||||||
|
foreach (var feedItem in context.Response.Items) {
|
||||||
|
// locate parts
|
||||||
|
var contentItem = feedItem.ContentItem;
|
||||||
|
var metadata = _contentManager.GetItemMetadata(contentItem);
|
||||||
|
var common = contentItem.Get<ICommonAspect>();
|
||||||
|
var routable = contentItem.Get<RoutableAspect>();
|
||||||
|
var body = contentItem.Get<BodyAspect>();
|
||||||
|
|
||||||
|
// standard fields
|
||||||
|
var link = "/todo";// metadata.DisplayRouteValues();
|
||||||
|
|
||||||
|
var title = metadata.DisplayText;
|
||||||
|
if (string.IsNullOrEmpty(title) && routable != null)
|
||||||
|
title = routable.Title;
|
||||||
|
|
||||||
|
var contentText = title;
|
||||||
|
if (body != null && !string.IsNullOrEmpty(body.Text))
|
||||||
|
contentText = body.Text;
|
||||||
|
|
||||||
|
DateTime? publishedDate = null;
|
||||||
|
if (common != null)
|
||||||
|
publishedDate = common.PublishedUtc ?? common.ModifiedUtc;
|
||||||
|
|
||||||
|
// TODO: author
|
||||||
|
|
||||||
|
|
||||||
|
// add to known formats
|
||||||
|
if (context.Format == "rss") {
|
||||||
|
feedItem.Element.SetElementValue("title", title);
|
||||||
|
feedItem.Element.SetElementValue("link", link);
|
||||||
|
feedItem.Element.SetElementValue("description", contentText);
|
||||||
|
if (publishedDate != null)
|
||||||
|
feedItem.Element.SetElementValue("pubDate", publishedDate);//TODO: format
|
||||||
|
//feedItem.Data.SetElementValue("description", contentText);
|
||||||
|
feedItem.Element.Add(new XElement("guid", new XAttribute("isPermaLink", "true"), new XText(link)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.FeedFormatter.AddProperty(context, feedItem, "link", link);
|
||||||
|
context.FeedFormatter.AddProperty(context, feedItem, "title", title);
|
||||||
|
context.FeedFormatter.AddProperty(context, feedItem, "description", contentText);
|
||||||
|
if (publishedDate != null)
|
||||||
|
context.FeedFormatter.AddProperty(context, feedItem, "published-date", Convert.ToString(publishedDate)); // format? cvt to generic T?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.Core.Common.Models;
|
||||||
|
using Orchard.Core.Common.Records;
|
||||||
|
using Orchard.Core.Feeds.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Core.Feeds.StandardQueries {
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class ContainerFeedQuery : IFeedQueryProvider, IFeedQuery {
|
||||||
|
private readonly IContentManager _contentManager;
|
||||||
|
|
||||||
|
public ContainerFeedQuery(IContentManager contentManager) {
|
||||||
|
_contentManager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedQueryMatch Match(FeedContext context) {
|
||||||
|
var containerIdValue = context.ValueProvider.GetValue("containerid");
|
||||||
|
if (containerIdValue == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new FeedQueryMatch { FeedQuery = this, Priority = -5 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(FeedContext context) {
|
||||||
|
var containerIdValue = context.ValueProvider.GetValue("containerid");
|
||||||
|
if (containerIdValue == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var limitValue = context.ValueProvider.GetValue("limit");
|
||||||
|
var limit = 20;
|
||||||
|
if (limitValue != null)
|
||||||
|
limit = (int)limitValue.ConvertTo(typeof(int));
|
||||||
|
|
||||||
|
var containerId = (int)containerIdValue.ConvertTo(typeof(int));
|
||||||
|
var container = _contentManager.Get(containerId);
|
||||||
|
|
||||||
|
var containerRoutable = container.As<RoutableAspect>();
|
||||||
|
var containerBody = container.As<BodyAspect>();
|
||||||
|
if (containerRoutable != null) {
|
||||||
|
context.FeedFormatter.AddProperty(context, null, "title", containerRoutable.Title);
|
||||||
|
context.FeedFormatter.AddProperty(context, null, "link", "/" + containerRoutable.Slug);
|
||||||
|
}
|
||||||
|
if (containerBody != null) {
|
||||||
|
context.FeedFormatter.AddProperty(context, null, "description", containerBody.Text);
|
||||||
|
}
|
||||||
|
else if (containerRoutable != null) {
|
||||||
|
context.FeedFormatter.AddProperty(context, null, "description", containerRoutable.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = _contentManager.Query()
|
||||||
|
.Where<CommonRecord>(x => x.Container == container.Record)
|
||||||
|
.OrderByDescending(x => x.PublishedUtc)
|
||||||
|
.Slice(0, limit);
|
||||||
|
|
||||||
|
foreach (var item in items) {
|
||||||
|
context.FeedFormatter.AddItem(context, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,6 +81,20 @@
|
|||||||
<Compile Include="Common\ViewModels\BodyEditorViewModel.cs" />
|
<Compile Include="Common\ViewModels\BodyEditorViewModel.cs" />
|
||||||
<Compile Include="Common\ViewModels\RoutableEditorViewModel.cs" />
|
<Compile Include="Common\ViewModels\RoutableEditorViewModel.cs" />
|
||||||
<Compile Include="Common\ViewModels\OwnerEditorViewModel.cs" />
|
<Compile Include="Common\ViewModels\OwnerEditorViewModel.cs" />
|
||||||
|
<Compile Include="Feeds\Controllers\FeedController.cs" />
|
||||||
|
<Compile Include="Feeds\Routes.cs" />
|
||||||
|
<Compile Include="Feeds\StandardQueries\ContainerFeedQuery.cs" />
|
||||||
|
<Compile Include="Feeds\StandardBuilders\CorePartsFeedItemBuilder.cs" />
|
||||||
|
<Compile Include="Feeds\IFeedFormatter.cs" />
|
||||||
|
<Compile Include="Feeds\IFeedFormatterProvider.cs" />
|
||||||
|
<Compile Include="Feeds\IFeedQuery.cs" />
|
||||||
|
<Compile Include="Feeds\IFeedQueryProvider.cs" />
|
||||||
|
<Compile Include="Feeds\IFeedItemBuilder.cs" />
|
||||||
|
<Compile Include="Feeds\Models\FeedContext.cs" />
|
||||||
|
<Compile Include="Feeds\Models\FeedItem.cs" />
|
||||||
|
<Compile Include="Feeds\Models\FeedResponse.cs" />
|
||||||
|
<Compile Include="Feeds\Rss\RssFeedFormat.cs" />
|
||||||
|
<Compile Include="Feeds\Rss\RssResult.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Scheduling\Records\ScheduledTaskRecord.cs" />
|
<Compile Include="Scheduling\Records\ScheduledTaskRecord.cs" />
|
||||||
<Compile Include="Scheduling\Services\PublishingTaskHandler.cs" />
|
<Compile Include="Scheduling\Services\PublishingTaskHandler.cs" />
|
||||||
@@ -152,6 +166,7 @@
|
|||||||
<Content Include="Common\Views\EditorTemplates\Parts\Common.Routable.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\Package.txt" />
|
||||||
<Content Include="Scheduling\Package.txt" />
|
<Content Include="Scheduling\Package.txt" />
|
||||||
<Content Include="Settings\Views\EditorTemplates\Items\Settings.Site.ascx" />
|
<Content Include="Settings\Views\EditorTemplates\Items\Settings.Site.ascx" />
|
||||||
<Content Include="Themes\Scripts\jquery-1.4.js" />
|
<Content Include="Themes\Scripts\jquery-1.4.js" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
|
|
||||||
namespace Orchard.Tasks {
|
namespace Orchard.Tasks {
|
||||||
@@ -7,6 +8,7 @@ namespace Orchard.Tasks {
|
|||||||
void Sweep();
|
void Sweep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UsedImplicitly]
|
||||||
public class BackgroundService : IBackgroundService {
|
public class BackgroundService : IBackgroundService {
|
||||||
private readonly IEnumerable<IBackgroundTask> _tasks;
|
private readonly IEnumerable<IBackgroundTask> _tasks;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user