Merge pull request #1 from tparnell8/rss

implement rss
This commit is contained in:
Tommy Parnell
2015-10-09 21:41:09 -04:00
18 changed files with 155 additions and 56 deletions

View File

@@ -2,8 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using DotNetMashup.Web.Extensions;
using DotNetMashup.Web.Global; using DotNetMashup.Web.Global;
using DotNetMashup.Web.Repositories; using DotNetMashup.Web.Model;
using DotNetMashup.Web.ViewModel; using DotNetMashup.Web.ViewModel;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
@@ -36,7 +39,7 @@ namespace DotNetMashup.Web.Controllers
{ {
return new HttpStatusCodeResult(404); 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<IActionResult> Tiles(int page = 1) public async Task<IActionResult> Tiles(int page = 1)
@@ -50,9 +53,42 @@ namespace DotNetMashup.Web.Controllers
return PartialView("Tiles", data); return PartialView("Tiles", data);
} }
[Route("api/tiles")]
public async Task<IEnumerable<IExternalData>> GetTiles()
{
return (await factory.GetData());
}
public IActionResult Error() public IActionResult Error()
{ {
return View("~/Views/Shared/Error.cshtml"); 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();
}
} }
} }

View File

@@ -2,11 +2,13 @@
namespace DotNetMashup.Web.Extensions namespace DotNetMashup.Web.Extensions
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
public static class StringHtmlExtensions public static class BclExtensions
{ {
/// <summary> /// <summary>
/// Truncates a string containing HTML to a number of text characters, keeping whole words. /// 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), return Regex.Replace(text.Truncate(maxCharacters),
@"\s+[^\s]+$", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled) + trailingText; @"\s+[^\s]+$", string.Empty, RegexOptions.IgnoreCase | RegexOptions.Compiled) + trailingText;
} }
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach(T item in enumeration)
{
action?.Invoke(item);
}
}
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
var i = 0;
return list.GroupBy(a => i++ % parts).AsEnumerable();
}
} }
} }

View File

@@ -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<IExternalData> 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;
}
}
}

View File

@@ -6,6 +6,7 @@ using DotNetMashup.Web.Global;
using DotNetMashup.Web.Model; using DotNetMashup.Web.Model;
using DotNetMashup.Web.Repositories; using DotNetMashup.Web.Repositories;
using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.Configuration;
namespace DotNetMashup.Web.Factory namespace DotNetMashup.Web.Factory
{ {
@@ -15,7 +16,7 @@ namespace DotNetMashup.Web.Factory
private List<IRepository> Repos; private List<IRepository> Repos;
private const string cacheKey = "data"; private const string cacheKey = "data";
public RepositoryFactory(IEnumerable<IBlogMetaData> data, ISiteSetting setting, IMemoryCache cache) public RepositoryFactory(IEnumerable<IBlogMetaData> data, ISiteSetting setting, IMemoryCache cache, IConfiguration config)
{ {
if(data == null) if(data == null)
{ {
@@ -31,7 +32,7 @@ namespace DotNetMashup.Web.Factory
} }
Repos = new List<IRepository>() Repos = new List<IRepository>()
{ {
new GitHubRepository(), new GitHubRepository(config),
new BlogPostRepository(data, setting) new BlogPostRepository(data, setting)
}; };
this.cache = cache; this.cache = cache;

View File

@@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Global namespace DotNetMashup.Web.Global
{ {
@@ -9,5 +6,7 @@ namespace DotNetMashup.Web.Global
{ {
List<string> Categories { get; } List<string> Categories { get; }
short AmountPerPage { get; } short AmountPerPage { get; }
string Title { get; }
string Descriptions { get; }
} }
} }

View File

@@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Global namespace DotNetMashup.Web.Global
{ {
@@ -10,5 +7,7 @@ namespace DotNetMashup.Web.Global
public short AmountPerPage { get { return 12; } } public short AmountPerPage { get { return 12; } }
public List<string> Categories { get; } = new List<string> { "c#", "csharp", "cs", "asp.net", "NancyFx", "Nancy", "vNext", "asp.net 5" }; public List<string> Categories { get; } = new List<string> { "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"; } }
} }
} }

View File

@@ -1,9 +1,4 @@
using System; namespace DotNetMashup.Web.Model
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model
{ {
public struct Author public struct Author
{ {

View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model namespace DotNetMashup.Web.Model
{ {
@@ -14,7 +11,7 @@ namespace DotNetMashup.Web.Model
public string Content { get; set; } public string Content { get; set; }
public string OriginalLink { get; set; } public Uri OriginalLink { get; set; }
public string Title { get; set; } public string Title { get; set; }
public DateTimeOffset PublishedDate { get; set; } public DateTimeOffset PublishedDate { get; set; }

View File

@@ -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 //stolen idea from: https://github.com/NancyFx/Nancy.Blog/blob/master/src/Nancy.Blog/Model/MetaData.cs
public class BlogMetaData : IBlogMetaData public class BlogMetaData : IBlogMetaData
@@ -10,6 +8,6 @@ namespace DotNetMashup.Web.Model
public string AuthorEmail { get; set; } public string AuthorEmail { get; set; }
public string ImageUrl { get; set; } public string ImageUrl { get; set; }
public string Id { get; set; } public string Id { get; set; }
public string BlogHomepage { get; set;} public string BlogHomepage { get; set; }
} }
} }

View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model namespace DotNetMashup.Web.Model
{ {
@@ -12,7 +9,7 @@ namespace DotNetMashup.Web.Model
public DateTimeOffset PublishedDate { get; set; } public DateTimeOffset PublishedDate { get; set; }
public string Summary { get; set; } public string Summary { get; set; }
public string Localink { get; set; } public string Localink { get; set; }
public string OriginalLink { get; set; } public Uri OriginalLink { get; set; }
public Author Author { get; set; } public Author Author { get; set; }
} }
} }

View File

@@ -1,9 +1,4 @@
using System; namespace DotNetMashup.Web.Model
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model
{ {
public interface IBlogMetaData public interface IBlogMetaData
{ {

View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DotNetMashup.Web.Model namespace DotNetMashup.Web.Model
{ {
@@ -9,7 +6,7 @@ namespace DotNetMashup.Web.Model
{ {
string Title { get; set; } string Title { get; set; }
string Content { get; set; } string Content { get; set; }
string OriginalLink { get; set; } Uri OriginalLink { get; set; }
Author Author { get; set; } Author Author { get; set; }
DateTimeOffset PublishedDate { get; set; } DateTimeOffset PublishedDate { get; set; }
} }

View File

@@ -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> Url { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
}
}

View File

@@ -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 var summary = x.Item.Summary == null
? ((TextSyndicationContent)x.Item.Content).Text ? ((TextSyndicationContent)x.Item.Content).Text

View File

@@ -1,15 +1,16 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetMashup.Web.Model; using DotNetMashup.Web.Model;
using Microsoft.Framework.Configuration;
using Octokit; using Octokit;
namespace DotNetMashup.Web.Repositories namespace DotNetMashup.Web.Repositories
{ {
public class GitHubRepository : IRepository public class GitHubRepository : IRepository
{ {
private readonly IConfiguration config;
public string FactoryName public string FactoryName
{ {
get get
@@ -18,13 +19,18 @@ namespace DotNetMashup.Web.Repositories
} }
} }
public GitHubRepository(IConfiguration config)
{
this.config = config;
}
public async Task<IEnumerable<IExternalData>> GetData() public async Task<IEnumerable<IExternalData>> GetData()
{ {
CommonMark.CommonMarkSettings.Default.AdditionalFeatures = CommonMark.CommonMarkAdditionalFeatures.All; CommonMark.CommonMarkSettings.Default.AdditionalFeatures = CommonMark.CommonMarkAdditionalFeatures.All;
var client = new GitHubClient(new ProductHeaderValue("dotnetmashup")) var client = new GitHubClient(new ProductHeaderValue("dotnetmashup"))
{ {
Credentials = new Credentials("151e2514adab9e8e44ab99fe8c71899fffa34caa") Credentials = new Credentials(config["github"])
}; };
var issues = await client.Issue.GetAllForRepository("aspnet", "Announcements"); var issues = await client.Issue.GetAllForRepository("aspnet", "Announcements");
return issues.Select(a => new GithubAnnouncement return issues.Select(a => new GithubAnnouncement
@@ -32,7 +38,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 }, 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), Content = CommonMark.CommonMarkConverter.Convert(a.Body),
Title = a.Title, Title = a.Title,
OriginalLink = a.HtmlUrl.AbsoluteUri, OriginalLink = a.HtmlUrl,
IssueNumber = a.Number, IssueNumber = a.Number,
PublishedDate = a.CreatedAt PublishedDate = a.CreatedAt
}); });

View File

@@ -1,6 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetMashup.Web.Model; using DotNetMashup.Web.Model;

View File

@@ -3,7 +3,6 @@ using System.IO;
using DotNetMashup.Web.Factory; using DotNetMashup.Web.Factory;
using DotNetMashup.Web.Global; using DotNetMashup.Web.Global;
using DotNetMashup.Web.Model; using DotNetMashup.Web.Model;
using DotNetMashup.Web.Repositories;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting;
using Microsoft.Dnx.Runtime; using Microsoft.Dnx.Runtime;
@@ -18,9 +17,13 @@ namespace DotNetMashup.Web
public class Startup public class Startup
{ {
private IEnumerable<IBlogMetaData> _feedData = null; private IEnumerable<IBlogMetaData> _feedData = null;
private IConfiguration config = null;
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{ {
config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
_feedData = JsonConvert.DeserializeObject<IEnumerable<BlogMetaData>>(File.ReadAllText(Path.Combine(appEnv.ApplicationBasePath, "blogfeed.json"))); _feedData = JsonConvert.DeserializeObject<IEnumerable<BlogMetaData>>(File.ReadAllText(Path.Combine(appEnv.ApplicationBasePath, "blogfeed.json")));
} }
@@ -29,6 +32,7 @@ namespace DotNetMashup.Web
// This method gets called by the runtime. // This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddInstance(config);
services.AddSingleton<ISiteSetting>(prov => services.AddSingleton<ISiteSetting>(prov =>
{ {
return new SiteSettings(); return new SiteSettings();

View File

@@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotNetMashup.Web.Model; using DotNetMashup.Web.Model;
namespace DotNetMashup.Web.ViewModel namespace DotNetMashup.Web.ViewModel