From a46940393d6b1995a187aa772f30893e307d70dc Mon Sep 17 00:00:00 2001 From: Tommy Parnell Date: Fri, 9 Oct 2015 21:30:31 -0400 Subject: [PATCH 1/2] implement rss --- .../Controllers/HomeController.cs | 40 ++++++++++++++++++- ...tringHtmlExtension.cs => BclExtensions.cs} | 18 ++++++++- .../Extensions/IExternalDataExtensions.cs | 33 +++++++++++++++ src/DotNetMashup.Web/Global/ISiteSetting.cs | 7 ++-- src/DotNetMashup.Web/Global/SiteSettings.cs | 7 ++-- src/DotNetMashup.Web/Model/Author.cs | 7 +--- .../Model/BaseExternalData.cs | 5 +-- src/DotNetMashup.Web/Model/BlogMetaData.cs | 6 +-- .../Model/BlogPostExternalData.cs | 5 +-- src/DotNetMashup.Web/Model/IBlogMetaData.cs | 7 +--- src/DotNetMashup.Web/Model/IExternalData.cs | 5 +-- src/DotNetMashup.Web/Model/sitemap.cs | 31 ++++++++++++++ .../Repositories/BlogPostRepository.cs | 2 +- .../Repositories/GitHubRepository.cs | 6 +-- .../Repositories/IRepository.cs | 4 +- src/DotNetMashup.Web/Startup.cs | 2 - .../ViewModel/MashupViewModel.cs | 7 +--- 17 files changed, 138 insertions(+), 54 deletions(-) rename src/DotNetMashup.Web/Extensions/{StringHtmlExtension.cs => BclExtensions.cs} (92%) create mode 100644 src/DotNetMashup.Web/Extensions/IExternalDataExtensions.cs create mode 100644 src/DotNetMashup.Web/Model/sitemap.cs diff --git a/src/DotNetMashup.Web/Controllers/HomeController.cs b/src/DotNetMashup.Web/Controllers/HomeController.cs index 980ff05..1ac5f03 100644 --- a/src/DotNetMashup.Web/Controllers/HomeController.cs +++ b/src/DotNetMashup.Web/Controllers/HomeController.cs @@ -2,8 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using System.Xml; +using System.Xml.Serialization; +using DotNetMashup.Web.Extensions; using DotNetMashup.Web.Global; -using DotNetMashup.Web.Repositories; +using DotNetMashup.Web.Model; using DotNetMashup.Web.ViewModel; using Microsoft.AspNet.Mvc; @@ -36,7 +39,7 @@ namespace DotNetMashup.Web.Controllers { return new HttpStatusCodeResult(404); } - return View(new MashupViewModel { CurrentPage = page, NextPage = data.Count > setting.AmountPerPage ? (int?)page + 1 : null, Header = "DotNet Mashups", Posts = data.Take(setting.AmountPerPage) }); + return View(new MashupViewModel { CurrentPage = page, NextPage = data.Count > setting.AmountPerPage ? (int?)page + 1 : null, Header = setting.Title, Posts = data.Take(setting.AmountPerPage) }); } public async Task Tiles(int page = 1) @@ -50,9 +53,42 @@ namespace DotNetMashup.Web.Controllers return PartialView("Tiles", data); } + [Route("api/tiles")] + public async Task> GetTiles() + { + return (await factory.GetData()); + } + public IActionResult Error() { return View("~/Views/Shared/Error.cshtml"); } + + [Route("sitemap.xml")] + public async Task sitemap() + { + Response.ContentType = "text/xml"; + var serializer = new XmlSerializer(typeof(Urlset)); + var set = new Urlset(); + var data = await GetTiles(); + var page = 0; + set.Url = data.Split(this.setting.AmountPerPage).Select(a => new Url() + { + Changefreq = "daily", + Lastmod = a.Select(b => b.PublishedDate).Max().ToString(), + Loc = Url.Action("Index", "Home", new { page = page++ }, this.Request.Scheme), + Priority = "1" + }).ToList(); + serializer.Serialize(Response.Body, set); + } + + [Route("rss")] + public async Task rss() + { + Response.ContentType = "text/xml"; + var writer = XmlWriter.Create(this.Response.Body, new XmlWriterSettings() { Async = true }); + (await factory.GetData()).ToRss().SaveAsRss20(writer); + await writer.FlushAsync(); + } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Extensions/StringHtmlExtension.cs b/src/DotNetMashup.Web/Extensions/BclExtensions.cs similarity index 92% rename from src/DotNetMashup.Web/Extensions/StringHtmlExtension.cs rename to src/DotNetMashup.Web/Extensions/BclExtensions.cs index 869e10a..0ed68fa 100644 --- a/src/DotNetMashup.Web/Extensions/StringHtmlExtension.cs +++ b/src/DotNetMashup.Web/Extensions/BclExtensions.cs @@ -2,11 +2,13 @@ namespace DotNetMashup.Web.Extensions { + using System; using System.Collections.Generic; + using System.Linq; using System.Text; using System.Text.RegularExpressions; - public static class StringHtmlExtensions + public static class BclExtensions { /// /// Truncates a string containing HTML to a number of text characters, keeping whole words. @@ -166,5 +168,19 @@ namespace DotNetMashup.Web.Extensions return Regex.Replace(text.Truncate(maxCharacters), @"\s+[^\s]+$", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled) + trailingText; } + + public static void ForEach(this IEnumerable enumeration, Action action) + { + foreach(T item in enumeration) + { + action?.Invoke(item); + } + } + + public static IEnumerable> Split(this IEnumerable list, int parts) + { + var i = 0; + return list.GroupBy(a => i++ % parts).AsEnumerable(); + } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Extensions/IExternalDataExtensions.cs b/src/DotNetMashup.Web/Extensions/IExternalDataExtensions.cs new file mode 100644 index 0000000..4f7158a --- /dev/null +++ b/src/DotNetMashup.Web/Extensions/IExternalDataExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceModel.Syndication; +using DotNetMashup.Web.Global; +using DotNetMashup.Web.Model; + +namespace DotNetMashup.Web.Extensions +{ + public static class IExternalDataExtensions + { + public static SyndicationFeed ToRss(this IEnumerable data) + { + var settings = new SiteSettings(); + var feed = new SyndicationFeed + { + Title = new TextSyndicationContent(settings.Title), + Id = "DotNet Mashup", + LastUpdatedTime = data.OrderByDescending(a => a.PublishedDate).FirstOrDefault().PublishedDate, + Description = new TextSyndicationContent(settings.Descriptions) + }; + var authors = data.Select(a => a.Author) + .Distinct() + .Select(a => new SyndicationPerson() { Name = a.Name, Email = a.Email, Uri = a.AuthorUrl }); + authors.ForEach(a => feed.Authors.Add(a)); + authors.ForEach(a => feed.Contributors.Add(a)); + feed.Links.Add(new SyndicationLink(new Uri("http://dotnetmashup.azurewebsites.net"))); + feed.Items = data.Select(a => new SyndicationItem(a.Title, a.Content, a.OriginalLink)).ToList(); + + return feed; + } + } +} \ No newline at end of file diff --git a/src/DotNetMashup.Web/Global/ISiteSetting.cs b/src/DotNetMashup.Web/Global/ISiteSetting.cs index d117d06..13036ba 100644 --- a/src/DotNetMashup.Web/Global/ISiteSetting.cs +++ b/src/DotNetMashup.Web/Global/ISiteSetting.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace DotNetMashup.Web.Global { @@ -9,5 +6,7 @@ namespace DotNetMashup.Web.Global { List Categories { get; } short AmountPerPage { get; } + string Title { get; } + string Descriptions { get; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Global/SiteSettings.cs b/src/DotNetMashup.Web/Global/SiteSettings.cs index 56911ec..90934b2 100644 --- a/src/DotNetMashup.Web/Global/SiteSettings.cs +++ b/src/DotNetMashup.Web/Global/SiteSettings.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace DotNetMashup.Web.Global { @@ -10,5 +7,7 @@ namespace DotNetMashup.Web.Global public short AmountPerPage { get { return 12; } } public List Categories { get; } = new List { "c#", "csharp", "cs", "asp.net", "NancyFx", "Nancy", "vNext", "asp.net 5" }; + public string Title { get { return "DotNet Mashups"; } } + public string Descriptions { get { return "Mashup of DotNet News"; } } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/Author.cs b/src/DotNetMashup.Web/Model/Author.cs index 3101abd..98986eb 100644 --- a/src/DotNetMashup.Web/Model/Author.cs +++ b/src/DotNetMashup.Web/Model/Author.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace DotNetMashup.Web.Model +namespace DotNetMashup.Web.Model { public struct Author { diff --git a/src/DotNetMashup.Web/Model/BaseExternalData.cs b/src/DotNetMashup.Web/Model/BaseExternalData.cs index 715ebdb..30da13e 100644 --- a/src/DotNetMashup.Web/Model/BaseExternalData.cs +++ b/src/DotNetMashup.Web/Model/BaseExternalData.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DotNetMashup.Web.Model { @@ -14,7 +11,7 @@ namespace DotNetMashup.Web.Model public string Content { get; set; } - public string OriginalLink { get; set; } + public Uri OriginalLink { get; set; } public string Title { get; set; } public DateTimeOffset PublishedDate { get; set; } diff --git a/src/DotNetMashup.Web/Model/BlogMetaData.cs b/src/DotNetMashup.Web/Model/BlogMetaData.cs index b41ea4f..29fae35 100644 --- a/src/DotNetMashup.Web/Model/BlogMetaData.cs +++ b/src/DotNetMashup.Web/Model/BlogMetaData.cs @@ -1,6 +1,4 @@ -using System; - -namespace DotNetMashup.Web.Model +namespace DotNetMashup.Web.Model { //stolen idea from: https://github.com/NancyFx/Nancy.Blog/blob/master/src/Nancy.Blog/Model/MetaData.cs public class BlogMetaData : IBlogMetaData @@ -10,6 +8,6 @@ namespace DotNetMashup.Web.Model public string AuthorEmail { get; set; } public string ImageUrl { get; set; } public string Id { get; set; } - public string BlogHomepage { get; set;} + public string BlogHomepage { get; set; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/BlogPostExternalData.cs b/src/DotNetMashup.Web/Model/BlogPostExternalData.cs index e92b54c..373ca1c 100644 --- a/src/DotNetMashup.Web/Model/BlogPostExternalData.cs +++ b/src/DotNetMashup.Web/Model/BlogPostExternalData.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DotNetMashup.Web.Model { @@ -12,7 +9,7 @@ namespace DotNetMashup.Web.Model public DateTimeOffset PublishedDate { get; set; } public string Summary { get; set; } public string Localink { get; set; } - public string OriginalLink { get; set; } + public Uri OriginalLink { get; set; } public Author Author { get; set; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/IBlogMetaData.cs b/src/DotNetMashup.Web/Model/IBlogMetaData.cs index 14d83d5..48417de 100644 --- a/src/DotNetMashup.Web/Model/IBlogMetaData.cs +++ b/src/DotNetMashup.Web/Model/IBlogMetaData.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace DotNetMashup.Web.Model +namespace DotNetMashup.Web.Model { public interface IBlogMetaData { diff --git a/src/DotNetMashup.Web/Model/IExternalData.cs b/src/DotNetMashup.Web/Model/IExternalData.cs index 7b73b6c..328c9dc 100644 --- a/src/DotNetMashup.Web/Model/IExternalData.cs +++ b/src/DotNetMashup.Web/Model/IExternalData.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DotNetMashup.Web.Model { @@ -9,7 +6,7 @@ namespace DotNetMashup.Web.Model { string Title { get; set; } string Content { get; set; } - string OriginalLink { get; set; } + Uri OriginalLink { get; set; } Author Author { get; set; } DateTimeOffset PublishedDate { get; set; } } diff --git a/src/DotNetMashup.Web/Model/sitemap.cs b/src/DotNetMashup.Web/Model/sitemap.cs new file mode 100644 index 0000000..ce68969 --- /dev/null +++ b/src/DotNetMashup.Web/Model/sitemap.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace DotNetMashup.Web.Model +{ + [XmlRoot(ElementName = "url", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public class Url + { + [XmlElement(ElementName = "loc", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public string Loc { get; set; } + + [XmlElement(ElementName = "lastmod", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public string Lastmod { get; set; } + + [XmlElement(ElementName = "changefreq", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public string Changefreq { get; set; } + + [XmlElement(ElementName = "priority", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public string Priority { get; set; } + } + + [XmlRoot(ElementName = "urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public class Urlset + { + [XmlElement(ElementName = "url", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")] + public List Url { get; set; } + + [XmlAttribute(AttributeName = "xmlns")] + public string Xmlns { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs b/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs index c6d4c39..5168a5a 100644 --- a/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs +++ b/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs @@ -57,7 +57,7 @@ namespace DotNetMashup.Web.Repositories } } - var originallink = link == null ? string.Empty : link.Uri.AbsoluteUri; + var originallink = link.Uri; var summary = x.Item.Summary == null ? ((TextSyndicationContent)x.Item.Content).Text diff --git a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs index bb08fe0..1bccedc 100644 --- a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs +++ b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; using System.Threading.Tasks; using DotNetMashup.Web.Model; using Octokit; @@ -32,7 +30,7 @@ namespace DotNetMashup.Web.Repositories Author = new Model.Author { Name = !string.IsNullOrWhiteSpace(a.User.Name) ? a.User.Name : a.User.Login, AuthorUrl = a.User.Url, ImageUrl = a.User.AvatarUrl, Email = a.User.Email }, Content = CommonMark.CommonMarkConverter.Convert(a.Body), Title = a.Title, - OriginalLink = a.HtmlUrl.AbsoluteUri, + OriginalLink = a.HtmlUrl, IssueNumber = a.Number, PublishedDate = a.CreatedAt }); diff --git a/src/DotNetMashup.Web/Repositories/IRepository.cs b/src/DotNetMashup.Web/Repositories/IRepository.cs index b23b847..e9f4d3e 100644 --- a/src/DotNetMashup.Web/Repositories/IRepository.cs +++ b/src/DotNetMashup.Web/Repositories/IRepository.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Threading.Tasks; using DotNetMashup.Web.Model; diff --git a/src/DotNetMashup.Web/Startup.cs b/src/DotNetMashup.Web/Startup.cs index 2949ad1..0539c13 100644 --- a/src/DotNetMashup.Web/Startup.cs +++ b/src/DotNetMashup.Web/Startup.cs @@ -3,12 +3,10 @@ using System.IO; using DotNetMashup.Web.Factory; using DotNetMashup.Web.Global; using DotNetMashup.Web.Model; -using DotNetMashup.Web.Repositories; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; using Microsoft.Dnx.Runtime; using Microsoft.Framework.Caching.Memory; -using Microsoft.Framework.Configuration; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; using Newtonsoft.Json; diff --git a/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs b/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs index e3fe8f4..dbf1745 100644 --- a/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs +++ b/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using DotNetMashup.Web.Model; namespace DotNetMashup.Web.ViewModel @@ -13,4 +10,4 @@ namespace DotNetMashup.Web.ViewModel public int? NextPage { get; set; } public IEnumerable Posts { get; set; } } -} +} \ No newline at end of file From b749a0c2c1114265a310f239d8c5b5e31958f09d Mon Sep 17 00:00:00 2001 From: Tommy Parnell Date: Fri, 9 Oct 2015 21:40:52 -0400 Subject: [PATCH 2/2] take github key through env var --- src/DotNetMashup.Web/Factory/RepositoryFactory.cs | 5 +++-- src/DotNetMashup.Web/Repositories/GitHubRepository.cs | 10 +++++++++- src/DotNetMashup.Web/Startup.cs | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/DotNetMashup.Web/Factory/RepositoryFactory.cs b/src/DotNetMashup.Web/Factory/RepositoryFactory.cs index 5efc270..b52e3a6 100644 --- a/src/DotNetMashup.Web/Factory/RepositoryFactory.cs +++ b/src/DotNetMashup.Web/Factory/RepositoryFactory.cs @@ -6,6 +6,7 @@ using DotNetMashup.Web.Global; using DotNetMashup.Web.Model; using DotNetMashup.Web.Repositories; using Microsoft.Framework.Caching.Memory; +using Microsoft.Framework.Configuration; namespace DotNetMashup.Web.Factory { @@ -15,7 +16,7 @@ namespace DotNetMashup.Web.Factory private List Repos; private const string cacheKey = "data"; - public RepositoryFactory(IEnumerable data, ISiteSetting setting, IMemoryCache cache) + public RepositoryFactory(IEnumerable data, ISiteSetting setting, IMemoryCache cache, IConfiguration config) { if(data == null) { @@ -31,7 +32,7 @@ namespace DotNetMashup.Web.Factory } Repos = new List() { - new GitHubRepository(), + new GitHubRepository(config), new BlogPostRepository(data, setting) }; this.cache = cache; diff --git a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs index 1bccedc..73569f4 100644 --- a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs +++ b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs @@ -2,12 +2,15 @@ using System.Linq; using System.Threading.Tasks; using DotNetMashup.Web.Model; +using Microsoft.Framework.Configuration; using Octokit; namespace DotNetMashup.Web.Repositories { public class GitHubRepository : IRepository { + private readonly IConfiguration config; + public string FactoryName { get @@ -16,13 +19,18 @@ namespace DotNetMashup.Web.Repositories } } + public GitHubRepository(IConfiguration config) + { + this.config = config; + } + public async Task> GetData() { CommonMark.CommonMarkSettings.Default.AdditionalFeatures = CommonMark.CommonMarkAdditionalFeatures.All; var client = new GitHubClient(new ProductHeaderValue("dotnetmashup")) { - Credentials = new Credentials("151e2514adab9e8e44ab99fe8c71899fffa34caa") + Credentials = new Credentials(config["github"]) }; var issues = await client.Issue.GetAllForRepository("aspnet", "Announcements"); return issues.Select(a => new GithubAnnouncement diff --git a/src/DotNetMashup.Web/Startup.cs b/src/DotNetMashup.Web/Startup.cs index 0539c13..3790070 100644 --- a/src/DotNetMashup.Web/Startup.cs +++ b/src/DotNetMashup.Web/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; using Microsoft.Dnx.Runtime; using Microsoft.Framework.Caching.Memory; +using Microsoft.Framework.Configuration; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; using Newtonsoft.Json; @@ -16,9 +17,13 @@ namespace DotNetMashup.Web public class Startup { private IEnumerable _feedData = null; + private IConfiguration config = null; public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) { + config = new ConfigurationBuilder() + .AddEnvironmentVariables() + .Build(); _feedData = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(appEnv.ApplicationBasePath, "blogfeed.json"))); } @@ -27,6 +32,7 @@ namespace DotNetMashup.Web // This method gets called by the runtime. public void ConfigureServices(IServiceCollection services) { + services.AddInstance(config); services.AddSingleton(prov => { return new SiteSettings();