diff --git a/src/DotNetMashup.Web/Controllers/HomeController.cs b/src/DotNetMashup.Web/Controllers/HomeController.cs index dea5487..dcc7769 100644 --- a/src/DotNetMashup.Web/Controllers/HomeController.cs +++ b/src/DotNetMashup.Web/Controllers/HomeController.cs @@ -2,38 +2,41 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using DotNetMashup.Web.Global; using DotNetMashup.Web.Repositories; +using DotNetMashup.Web.ViewModel; using Microsoft.AspNet.Mvc; namespace DotNetMashup.Web.Controllers { public class HomeController : Controller { + private readonly ISiteSetting setting; private readonly Factory.RepositoryFactory factory; - public HomeController(Factory.RepositoryFactory factory) + public HomeController(Factory.RepositoryFactory factory, ISiteSetting setting) { + if(factory == null) + { + throw new ArgumentNullException("factory"); + } + if(setting == null) + { + throw new ArgumentNullException("setting"); + } this.factory = factory; + this.setting = setting; } - public async Task Index() + public async Task Index(int page = 1) { - var data = await factory.GetData(); - return View(); - } - - public IActionResult About() - { - ViewData["Message"] = "Your application description page."; - - return View(); - } - - public IActionResult Contact() - { - ViewData["Message"] = "Your contact page."; - - return View(); + var factoryData = (await factory.GetData()); + var data = factoryData.OrderByDescending(a => a.PublishedDate).Skip((page - 1) * setting.AmountPerPage).Take(setting.AmountPerPage * 2).ToList(); + if(data.Count < 1) + { + return new HttpStatusCodeResult(404); + } + return View(new MashupViewModel { CurrentPage = 1, NextPage = data.Count > setting.AmountPerPage ? (int?)page + 1: null, Header = "DotNet Mashups", Posts = data.Take(setting.AmountPerPage)}); } public IActionResult Error() diff --git a/src/DotNetMashup.Web/Factory/RepositoryFactory.cs b/src/DotNetMashup.Web/Factory/RepositoryFactory.cs index 0e2395f..5efc270 100644 --- a/src/DotNetMashup.Web/Factory/RepositoryFactory.cs +++ b/src/DotNetMashup.Web/Factory/RepositoryFactory.cs @@ -37,13 +37,13 @@ namespace DotNetMashup.Web.Factory this.cache = cache; } - public async Task> GetData() + public async Task> GetData() { - var cachedData = this.cache.Get>(cacheKey); - if(cachedData != null && cachedData.Count > 0) return cachedData; + var cachedData = this.cache.Get>(cacheKey); + if(cachedData != null && cachedData.Any()) return cachedData; var tasks = Repos.Select(a => a.GetData()); await Task.WhenAll(tasks); - var result = tasks.SelectMany(a => a.Result).OrderBy(a => a.PublishedDate).ToList(); + var result = tasks.SelectMany(a => a.Result).ToList(); cache.Set(cacheKey, result, new MemoryCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddHours(4) }); return result; } diff --git a/src/DotNetMashup.Web/Global/ISiteSetting.cs b/src/DotNetMashup.Web/Global/ISiteSetting.cs index 79b4a14..d117d06 100644 --- a/src/DotNetMashup.Web/Global/ISiteSetting.cs +++ b/src/DotNetMashup.Web/Global/ISiteSetting.cs @@ -8,5 +8,6 @@ namespace DotNetMashup.Web.Global public interface ISiteSetting { List Categories { get; } + short AmountPerPage { get; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Global/SiteSettings.cs b/src/DotNetMashup.Web/Global/SiteSettings.cs index 05ac41d..56911ec 100644 --- a/src/DotNetMashup.Web/Global/SiteSettings.cs +++ b/src/DotNetMashup.Web/Global/SiteSettings.cs @@ -7,6 +7,8 @@ namespace DotNetMashup.Web.Global { public class SiteSettings : ISiteSetting { + public short AmountPerPage { get { return 12; } } + public List Categories { get; } = new List { "c#", "csharp", "cs", "asp.net", "NancyFx", "Nancy", "vNext", "asp.net 5" }; } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/BaseExternalData.cs b/src/DotNetMashup.Web/Model/BaseExternalData.cs index d7e4921..715ebdb 100644 --- a/src/DotNetMashup.Web/Model/BaseExternalData.cs +++ b/src/DotNetMashup.Web/Model/BaseExternalData.cs @@ -17,6 +17,6 @@ namespace DotNetMashup.Web.Model public string OriginalLink { get; set; } public string Title { get; set; } - public DateTime PublishedDate { get; set; } + public DateTimeOffset PublishedDate { get; set; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/BlogMetaData.cs b/src/DotNetMashup.Web/Model/BlogMetaData.cs index 46fddb6..b41ea4f 100644 --- a/src/DotNetMashup.Web/Model/BlogMetaData.cs +++ b/src/DotNetMashup.Web/Model/BlogMetaData.cs @@ -1,12 +1,15 @@ -namespace DotNetMashup.Web.Model +using System; + +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 { public string FeedUrl { get; set; } - public string Author { get; set; } + public string AuthorName { get; set; } public string AuthorEmail { get; set; } - public string GravatarUrl { get; set; } + public string ImageUrl { get; set; } public string Id { 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 new file mode 100644 index 0000000..e92b54c --- /dev/null +++ b/src/DotNetMashup.Web/Model/BlogPostExternalData.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace DotNetMashup.Web.Model +{ + public class BlogPostExternalData : IExternalData + { + public string Title { get; set; } + public string Content { get; set; } + public DateTimeOffset PublishedDate { get; set; } + public string Summary { get; set; } + public string Localink { get; set; } + public string OriginalLink { get; set; } + public Author Author { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/GithubAnnouncement.cs b/src/DotNetMashup.Web/Model/GithubAnnouncement.cs index aa15ecc..7260b40 100644 --- a/src/DotNetMashup.Web/Model/GithubAnnouncement.cs +++ b/src/DotNetMashup.Web/Model/GithubAnnouncement.cs @@ -2,5 +2,6 @@ { public class GithubAnnouncement : BaseExternalData { + public int IssueNumber { 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 025e408..14d83d5 100644 --- a/src/DotNetMashup.Web/Model/IBlogMetaData.cs +++ b/src/DotNetMashup.Web/Model/IBlogMetaData.cs @@ -8,9 +8,10 @@ namespace DotNetMashup.Web.Model public interface IBlogMetaData { string FeedUrl { get; set; } - string Author { get; set; } + string AuthorName { get; set; } string AuthorEmail { get; set; } - string GravatarUrl { get; set; } + string ImageUrl { get; set; } string Id { get; set; } + string BlogHomepage { get; set; } } } \ No newline at end of file diff --git a/src/DotNetMashup.Web/Model/IExternalData.cs b/src/DotNetMashup.Web/Model/IExternalData.cs index 3d8e974..7b73b6c 100644 --- a/src/DotNetMashup.Web/Model/IExternalData.cs +++ b/src/DotNetMashup.Web/Model/IExternalData.cs @@ -11,6 +11,6 @@ namespace DotNetMashup.Web.Model string Content { get; set; } string OriginalLink { get; set; } Author Author { get; set; } - DateTime PublishedDate { get; set; } + DateTimeOffset PublishedDate { 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 28a7684..f621582 100644 --- a/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs +++ b/src/DotNetMashup.Web/Repositories/BlogPostRepository.cs @@ -18,12 +18,10 @@ namespace DotNetMashup.Web.Repositories private readonly IMemoryCache cache; private readonly IEnumerable _data; - private const string cacheKey = "blogposts"; public BlogPostRepository(IEnumerable data, ISiteSetting setting) { this._data = data; - this.cache = cache; this.setting = setting; } @@ -45,7 +43,7 @@ namespace DotNetMashup.Web.Repositories .Select(x => { var metaauthor = _data.First(y => y.Id == x.Id); - var authorname = metaauthor.Author; + var authorname = metaauthor.AuthorName; var authoremail = metaauthor.AuthorEmail; var link = x.Item.Links.FirstOrDefault(y => y.RelationshipType == "alternate"); @@ -85,18 +83,17 @@ namespace DotNetMashup.Web.Repositories content = summary; } - return new BlogPost + return new BlogPostExternalData { Title = x.Item.Title.Text, Summary = truncatedSummary, - Author = new Author { Email = authoremail, Name = authorname }, + Author = new Author { Email = authoremail, Name = authorname, ImageUrl = metaauthor.ImageUrl, AuthorUrl = metaauthor.FeedUrl }, Localink = locallink, OriginalLink = originallink, PublishedDate = x.Item.PublishDate.DateTime, Content = content }; - }) - .ToList(); + }); return data; } diff --git a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs index 7ca6c50..bb08fe0 100644 --- a/src/DotNetMashup.Web/Repositories/GitHubRepository.cs +++ b/src/DotNetMashup.Web/Repositories/GitHubRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using DotNetMashup.Web.Model; using Octokit; @@ -19,14 +20,21 @@ namespace DotNetMashup.Web.Repositories public async Task> GetData() { - var client = new GitHubClient(new ProductHeaderValue("dotnetmashup")); + CommonMark.CommonMarkSettings.Default.AdditionalFeatures = CommonMark.CommonMarkAdditionalFeatures.All; + + var client = new GitHubClient(new ProductHeaderValue("dotnetmashup")) + { + Credentials = new Credentials("151e2514adab9e8e44ab99fe8c71899fffa34caa") + }; var issues = await client.Issue.GetAllForRepository("aspnet", "Announcements"); return issues.Select(a => new GithubAnnouncement { - 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 = a.Body, + 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.Url.AbsoluteUri + OriginalLink = a.HtmlUrl.AbsoluteUri, + IssueNumber = a.Number, + PublishedDate = a.CreatedAt }); } } diff --git a/src/DotNetMashup.Web/Startup.cs b/src/DotNetMashup.Web/Startup.cs index 5ac1f65..2949ad1 100644 --- a/src/DotNetMashup.Web/Startup.cs +++ b/src/DotNetMashup.Web/Startup.cs @@ -17,19 +17,14 @@ namespace DotNetMashup.Web { public class Startup { - private IEnumerable _feedData = null; + private IEnumerable _feedData = null; public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) { - // Setup configuration sources. - var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath) - .AddJsonFile("config.json") - .AddEnvironmentVariables(); - Configuration = builder.Build(); _feedData = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(appEnv.ApplicationBasePath, "blogfeed.json"))); } - public IConfigurationRoot Configuration { get; set; } + //public IConfigurationRoot Configuration { get; set; } // This method gets called by the runtime. public void ConfigureServices(IServiceCollection services) diff --git a/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs b/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs index 22b4d33..e3fe8f4 100644 --- a/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs +++ b/src/DotNetMashup.Web/ViewModel/MashupViewModel.cs @@ -9,6 +9,8 @@ namespace DotNetMashup.Web.ViewModel public class MashupViewModel { public string Header { get; set; } - public IEnumerable posts { get; set; } + public int CurrentPage { get; set; } + public int? NextPage { get; set; } + public IEnumerable Posts { get; set; } } } diff --git a/src/DotNetMashup.Web/Views/Home/Index.cshtml b/src/DotNetMashup.Web/Views/Home/Index.cshtml index 1a0fa32..63bfee4 100644 --- a/src/DotNetMashup.Web/Views/Home/Index.cshtml +++ b/src/DotNetMashup.Web/Views/Home/Index.cshtml @@ -1,104 +1,21 @@ -@{ - ViewData["Title"] = "Home Page"; +@model DotNetMashup.Web.ViewModel.MashupViewModel + +@{ + ViewData["Title"] = "Dot Net Mashups!"; } - -
-
-

Application uses

-
    -
  • Sample pages using ASP.NET 5 (MVC 6)
  • -
  • Gulp and Bower for managing client-side resources
  • -
  • Theming using Bootstrap
  • -
+@await Html.PartialAsync("Tiles", Model.Posts) + +
+
+@if(Model.NextPage.HasValue) +{ + - - - -
+ + + + +} \ No newline at end of file diff --git a/src/DotNetMashup.Web/Views/Home/Tiles.cshtml b/src/DotNetMashup.Web/Views/Home/Tiles.cshtml new file mode 100644 index 0000000..0316578 --- /dev/null +++ b/src/DotNetMashup.Web/Views/Home/Tiles.cshtml @@ -0,0 +1,14 @@ +@model IEnumerable + +@{ + ViewData["Title"] = "Dot Net Mashups!"; +} +
+ + @foreach(var x in Model) + { +
+ @(await Html.PartialAsync("ExternalData", x)) +
+ } +
\ No newline at end of file diff --git a/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/BlogPostExternalData.cshtml b/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/BlogPostExternalData.cshtml new file mode 100644 index 0000000..44dd3ed --- /dev/null +++ b/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/BlogPostExternalData.cshtml @@ -0,0 +1,15 @@ +@model DotNetMashup.Web.Model.BlogPostExternalData + + +
+
+
+

@Model.Author.Name

+
+
+
+

@Model.Title

+

@Html.Raw(Model.Content)

+
+
+
\ No newline at end of file diff --git a/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/GithubAnnouncement.cshtml b/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/GithubAnnouncement.cshtml new file mode 100644 index 0000000..293d705 --- /dev/null +++ b/src/DotNetMashup.Web/Views/Shared/DisplayTemplates/GithubAnnouncement.cshtml @@ -0,0 +1,11 @@ +@model DotNetMashup.Web.Model.GithubAnnouncement + +
+
+
+

@Model.Author.Name #@Model.IssueNumber

+
+
+

@Html.Raw(@Model.Content)

+
+
\ No newline at end of file diff --git a/src/DotNetMashup.Web/Views/Shared/ExternalData.cshtml b/src/DotNetMashup.Web/Views/Shared/ExternalData.cshtml new file mode 100644 index 0000000..39fadfa --- /dev/null +++ b/src/DotNetMashup.Web/Views/Shared/ExternalData.cshtml @@ -0,0 +1,3 @@ +@model DotNetMashup.Web.Model.IExternalData + +@Html.DisplayFor(a => a) \ No newline at end of file diff --git a/src/DotNetMashup.Web/Views/Shared/_Layout.cshtml b/src/DotNetMashup.Web/Views/Shared/_Layout.cshtml index e08b886..1b3fa93 100644 --- a/src/DotNetMashup.Web/Views/Shared/_Layout.cshtml +++ b/src/DotNetMashup.Web/Views/Shared/_Layout.cshtml @@ -1,80 +1,61 @@  - - - - @ViewData["Title"] - DotNetMashup.Web + + + + @ViewData["Title"] - DotNetMashup.Web - - - - - - - - - - - - - -
- @RenderBody() -
-
-

© 2015 - DotNetMashup.Web

-
-
+ + + + + + + + + + + + + +
+ @RenderBody() +
+
+

© 2015 - DotNetMashup.Web

+
- - - - - - - - - - - - - - + + + + + + + + + + + + + + - @RenderSection("scripts", required: false) - - + @RenderSection("scripts", required: false) + + \ No newline at end of file diff --git a/src/DotNetMashup.Web/blogfeed.json b/src/DotNetMashup.Web/blogfeed.json index 1001e49..d07fad8 100644 --- a/src/DotNetMashup.Web/blogfeed.json +++ b/src/DotNetMashup.Web/blogfeed.json @@ -2,8 +2,9 @@ { "id": "tparnell", "feedurl": "https://blog.tommyparnell.com/rss/", - "author": "Tommy Parnell", - "authoremail": "tparnell8@gmail.com", - "gravatarurl": "http://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061.png?s=128" + "authorName": "Tommy Parnell", + "authorEmail": "tparnell8@gmail.com", + "imageUrl": "http://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061.png?s=128", + "blogHomepage": "https://blog.tommyparnell.com" } ] \ No newline at end of file diff --git a/src/DotNetMashup.Web/package.json b/src/DotNetMashup.Web/package.json index d4d71a9..9e53931 100644 --- a/src/DotNetMashup.Web/package.json +++ b/src/DotNetMashup.Web/package.json @@ -6,6 +6,7 @@ "gulp-concat": "2.5.2", "gulp-cssmin": "0.1.7", "gulp-uglify": "1.2.0", - "rimraf": "2.2.8" + "rimraf": "2.2.8", + "font-awesome": "4.4.0" } } diff --git a/src/DotNetMashup.Web/project.json b/src/DotNetMashup.Web/project.json index 03b406b..cc6461a 100644 --- a/src/DotNetMashup.Web/project.json +++ b/src/DotNetMashup.Web/project.json @@ -17,7 +17,8 @@ "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta7", "Newtonsoft.Json": "7.0.1", "TweetinviAPI": "0.9.9.7", - "Octokit": "0.16.0" + "Octokit": "0.16.0", + "CommonMark.NET": "0.9.1" }, "commands": {