mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +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:
57
src/Orchard.Web/Core/Feeds/Controllers/FeedController.cs
Normal file
57
src/Orchard.Web/Core/Feeds/Controllers/FeedController.cs
Normal file
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
13
src/Orchard.Web/Core/Feeds/IFeedFormatter.cs
Normal file
13
src/Orchard.Web/Core/Feeds/IFeedFormatter.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
12
src/Orchard.Web/Core/Feeds/IFeedFormatterProvider.cs
Normal file
12
src/Orchard.Web/Core/Feeds/IFeedFormatterProvider.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
11
src/Orchard.Web/Core/Feeds/IFeedItemBuilder.cs
Normal file
11
src/Orchard.Web/Core/Feeds/IFeedItemBuilder.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
7
src/Orchard.Web/Core/Feeds/IFeedQuery.cs
Normal file
7
src/Orchard.Web/Core/Feeds/IFeedQuery.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Orchard.Core.Feeds.Models;
|
||||
|
||||
namespace Orchard.Core.Feeds {
|
||||
public interface IFeedQuery {
|
||||
void Execute(FeedContext context);
|
||||
}
|
||||
}
|
14
src/Orchard.Web/Core/Feeds/IFeedQueryProvider.cs
Normal file
14
src/Orchard.Web/Core/Feeds/IFeedQueryProvider.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
22
src/Orchard.Web/Core/Feeds/Models/FeedContext.cs
Normal file
22
src/Orchard.Web/Core/Feeds/Models/FeedContext.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
9
src/Orchard.Web/Core/Feeds/Models/FeedItem.cs
Normal file
9
src/Orchard.Web/Core/Feeds/Models/FeedItem.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
15
src/Orchard.Web/Core/Feeds/Models/FeedResponse.cs
Normal file
15
src/Orchard.Web/Core/Feeds/Models/FeedResponse.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
1
src/Orchard.Web/Core/Feeds/Package.txt
Normal file
1
src/Orchard.Web/Core/Feeds/Package.txt
Normal file
@@ -0,0 +1 @@
|
||||
name: Feeds
|
34
src/Orchard.Web/Core/Feeds/Rss/Routes.cs
Normal file
34
src/Orchard.Web/Core/Feeds/Rss/Routes.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
src/Orchard.Web/Core/Feeds/Rss/RssFeedFormat.cs
Normal file
55
src/Orchard.Web/Core/Feeds/Rss/RssFeedFormat.cs
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
23
src/Orchard.Web/Core/Feeds/Rss/RssResult.cs
Normal file
23
src/Orchard.Web/Core/Feeds/Rss/RssResult.cs
Normal file
@@ -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\RoutableEditorViewModel.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="Scheduling\Records\ScheduledTaskRecord.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.Body.ascx" />
|
||||
<Content Include="Common\Views\EditorTemplates\Parts\Common.Owner.ascx" />
|
||||
<Content Include="Feeds\Package.txt" />
|
||||
<Content Include="Scheduling\Package.txt" />
|
||||
<Content Include="Settings\Views\EditorTemplates\Items\Settings.Site.ascx" />
|
||||
<Content Include="Themes\Scripts\jquery-1.4.js" />
|
||||
|
Reference in New Issue
Block a user