diff --git a/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs b/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs index 493c2facc..4ef36c818 100644 --- a/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs +++ b/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs @@ -9,7 +9,6 @@ using Orchard.ContentManagement; using Orchard.Core.Feeds.Models; using Orchard.Mvc.Extensions; using Orchard.Services; -using Orchard.Utility.Extensions; namespace Orchard.Core.Feeds.StandardBuilders { [UsedImplicitly] @@ -35,9 +34,7 @@ namespace Orchard.Core.Feeds.StandardBuilders { _contentManager.GetItemMetadata(feedItem.Item), _htmlFilters); - - // TODO: author - + // author is intentionally left empty as it could result in unwanted spam // add to known formats if (context.Format == "rss") { diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Migrations.cs new file mode 100644 index 000000000..709706f4e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Migrations.cs @@ -0,0 +1,19 @@ +using Orchard.ContentManagement.MetaData; +using Orchard.Core.Contents.Extensions; +using Orchard.Data.Migration; + +namespace Orchard.Tokens { + public class Migrations : DataMigrationImpl { + + public int Create() { + + ContentDefinitionManager.AlterPartDefinition("RssPart", + cfg => cfg + .Attachable() + .WithDescription("Attach to a content type to provide custom values in RSS feeds.") + ); + + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Models/RssPart.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Models/RssPart.cs new file mode 100644 index 000000000..77d86e236 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Models/RssPart.cs @@ -0,0 +1,6 @@ +using Orchard.ContentManagement; + +namespace Orchard.Tokens.Models { + public class RssPart : ContentPart { + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt b/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt index 0449c3a8e..e7af0aa2b 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt @@ -9,4 +9,5 @@ Features: Orchard.Tokens: Name: Tokens Description: Provides a system for performing string replacements with common site values. - Category: Content \ No newline at end of file + Category: Content + Dependencies: Core \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Orchard.Tokens.csproj b/src/Orchard.Web/Modules/Orchard.Tokens/Orchard.Tokens.csproj index 20b7004ca..7f08c2b2f 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Orchard.Tokens.csproj +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Orchard.Tokens.csproj @@ -77,6 +77,8 @@ + + @@ -94,12 +96,15 @@ + + + @@ -122,6 +127,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RssPartFeedItemBuilder.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RssPartFeedItemBuilder.cs new file mode 100644 index 000000000..9b0fd3f4f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RssPartFeedItemBuilder.cs @@ -0,0 +1,202 @@ +using System; +using System.Linq; +using System.Xml.Linq; +using Orchard.ContentManagement; +using Orchard.Core.Feeds; +using Orchard.Core.Feeds.Models; +using Orchard.Tokens.Models; +using Orchard.Tokens.Settings; + +namespace Orchard.Tokens.Providers { + public class RssPartFeedItemBuilder : IFeedItemBuilder { + private readonly ITokenizer _tokenizer; + + public RssPartFeedItemBuilder( + ITokenizer tokenizer) { + _tokenizer = tokenizer; + } + + public void Populate(FeedContext context) { + foreach (var feedItem in context.Response.Items.OfType>()) { + var rssPart = feedItem.Item.As(); + if (rssPart == null) { + continue; + } + + var settings = rssPart.TypePartDefinition.Settings.GetModel(); + + // add to known formats + if (context.Format == "rss") { + + if (!String.IsNullOrWhiteSpace(settings.Title)) { + var title = feedItem.Element.Element("title"); + + if (settings.Title == "-") { + if (title != null) { + title.Remove(); + } + } + else { + if (title == null) { + feedItem.Element.Add(title = new XElement("title")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + title.Value = _tokenizer.Replace(settings.Title, new { Content = item.Item, Text = title.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.Author)) { + var author = feedItem.Element.Element("author"); + + if (settings.Author == "-") { + if (author != null) { + author.Remove(); + } + } + else { + if (author == null) { + feedItem.Element.Add(author = new XElement("author")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + author.Value = _tokenizer.Replace(settings.Title, new { Content = item.Item, Text = author.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.Description)) { + var description = feedItem.Element.Element("description"); + + if (settings.Description == "-") { + if (description != null) { + description.Remove(); + } + } + else { + if (description == null) { + feedItem.Element.Add(description = new XElement("description")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + description.Value = _tokenizer.Replace(settings.Description, new { Content = item.Item, Text = description.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.Enclosure)) { + var enclosure = feedItem.Element.Element("enclosure"); + + if (settings.Enclosure == "-") { + if (enclosure != null) { + enclosure.Remove(); + } + } + else { + if (enclosure == null) { + feedItem.Element.Add(enclosure = new XElement("enclosure")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + enclosure.Value = _tokenizer.Replace(settings.Enclosure, new { Content = item.Item, Text = enclosure.Value }); + }); + } + } + + + if (!String.IsNullOrWhiteSpace(settings.Link)) { + var link = feedItem.Element.Element("link"); + + if (settings.Link == "-") { + if (link != null) { + link.Remove(); + } + } + else { + if (link == null) { + feedItem.Element.Add(link = new XElement("link")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + link.Value = _tokenizer.Replace(settings.Link, new { Content = item.Item, Text = link.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.PubDate)) { + var pubDate = feedItem.Element.Element("pubDate"); + + if (settings.PubDate == "-") { + if (pubDate != null) { + pubDate.Remove(); + } + } + else { + if (pubDate == null) { + feedItem.Element.Add(pubDate = new XElement("pubDate")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + pubDate.Value = _tokenizer.Replace(settings.PubDate, new { Content = item.Item, Text = pubDate.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.Source)) { + var source = feedItem.Element.Element("source"); + + if (settings.Source == "-") { + if (source != null) { + source.Remove(); + } + } + else { + if (source == null) { + feedItem.Element.Add(source = new XElement("source")); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + source.Value = _tokenizer.Replace(settings.Source, new { Content = item.Item, Text = source.Value }); + }); + } + } + + if (!String.IsNullOrWhiteSpace(settings.Category)) { + var categories = feedItem.Element.Elements("category").ToArray(); + + var currentValue = String.Join(",", categories.Select(x => x.Value).ToArray()); + + if (settings.Category == "-") { + foreach (var category in categories) { + category.Remove(); + } + } + else { + foreach (var category in categories) { + category.Remove(); + } + + FeedItem item = feedItem; + context.Response.Contextualize(requestContext => { + + var newValue = _tokenizer.Replace(settings.Category, new { Content = item.Item, Text = currentValue }); + + foreach (var value in newValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { + feedItem.Element.Add(new XElement("category", value)); + } + }); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/RssPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Tokens/RssPartDriver.cs new file mode 100644 index 000000000..738552dc4 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/RssPartDriver.cs @@ -0,0 +1,7 @@ +using Orchard.ContentManagement.Drivers; +using Orchard.Tokens.Models; + +namespace Orchard.Tokens { + public class RssPartDriver : ContentPartDriver { + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Settings/RssPartSettings.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Settings/RssPartSettings.cs new file mode 100644 index 000000000..bcae37ad1 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Settings/RssPartSettings.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; + +namespace Orchard.Tokens.Settings { + public class RssPartSettings { + + public string Title { get; set; } + public string Link { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public string Category { get; set; } + public string Enclosure { get; set; } + public string PubDate { get; set; } + public string Source { get; set; } + } + + public class RssPartSettingsEvents : ContentDefinitionEditorEventsBase { + public override IEnumerable TypePartEditor(ContentTypePartDefinition definition) { + if (definition.PartDefinition.Name == "RssPart") { + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + } + + public override IEnumerable TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel upOwnerModel) { + if (builder.Name == "RssPart") { + var model = new RssPartSettings(); + if (upOwnerModel.TryUpdateModel(model, "RssPartSettings", null, null)) { + builder.WithSetting("RssPartSettings.Title", model.Title); + builder.WithSetting("RssPartSettings.Link", model.Link); + builder.WithSetting("RssPartSettings.Description", model.Description); + builder.WithSetting("RssPartSettings.Author", model.Author); + builder.WithSetting("RssPartSettings.Category", model.Category); + builder.WithSetting("RssPartSettings.Enclosure", model.Enclosure); + builder.WithSetting("RssPartSettings.PubDate", model.PubDate); + builder.WithSetting("RssPartSettings.Source", model.Source); + } + + yield return DefinitionTemplate(model); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Views/DefinitionTemplates/RssPartSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Tokens/Views/DefinitionTemplates/RssPartSettings.cshtml new file mode 100644 index 000000000..a3267ff01 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Views/DefinitionTemplates/RssPartSettings.cshtml @@ -0,0 +1,46 @@ +@model Orchard.Tokens.Settings.RssPartSettings + + + @T(" Use '-' to remove the tag, leave empty to keep untouched, or use the 'Text' text token for the current value.") + + @T("Title") + @Html.TextBoxFor(m => m.Title, new { @class = "tokenized text medium" }) + @T("The title field of the RSS item.") + + + @T("Link") + @Html.TextBoxFor(m => m.Link, new { @class = "tokenized text medium" }) + @T("The link field of the RSS item") + + + @T("Description") + @Html.TextBoxFor(m => m.Description, new { @class = "tokenized text medium" }) + @T("The description field of the RSS item") + + + @T("Author") + @Html.TextBoxFor(m => m.Author, new { @class = "tokenized text medium" }) + @T("The author field of the RSS item") + + + @T("Category") + @Html.TextBoxFor(m => m.Category, new { @class = "tokenized text medium" }) + @T("The category field of the RSS item") + + + @T("Enclosure") + @Html.TextBoxFor(m => m.Enclosure, new { @class = "tokenized text medium" }) + @T("The enclosure field of the RSS item. This is usually a html tag like ") + + + @T("PubDate") + @Html.TextBoxFor(m => m.PubDate, new { @class = "tokenized text medium" }) + @T("The pubDate field of the RSS item") + + + @T("Source") + @Html.TextBoxFor(m => m.Source, new { @class = "tokenized text medium" }) + @T("The source field of the RSS item") + + +