Skip to content

Commit

Permalink
Add Open Graph protocol (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
petervandenhout authored Aug 12, 2019
1 parent 55613f8 commit 34686c4
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 44 deletions.
1 change: 1 addition & 0 deletions samples/Opw.PineBlog.Sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
},
"PineBlogOptions": {
"Title": "PineBlog",
"Description": "A blogging engine based on ASP.NET Core MVC Razor Pages and Entity Framework Core",
"CoverUrl": "/images/woods.gif",
"CoverCaption": "Battle background for the Misty Woods in the game Shadows of Adam by Tim Wendorf",
"CoverLink": "http://pixeljoint.com/pixelart/94359.htm",
Expand Down
12 changes: 3 additions & 9 deletions src/Opw.PineBlog.RazorPages/Areas/Blog/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
@page
@model IndexModel
@{
var pageCoverModel = new Opw.PineBlog.RazorPages.Models.PageCoverModel(
Model.PostList.Blog.Title,
Model.PostList.Blog.CoverUrl,
Model.PostList.Blog.CoverCaption,
Model.PostList.Blog.CoverLink,
Model.PostList.PostListType,
Model.PostList.Category);
@section head {
<partial name="_Metadata" model="@Model.Metadata" />
}

<partial name="_PageCover" model="pageCoverModel" />
<partial name="_PageCover" model="@Model.PageCover" />

<div class="page-content">
<div class="container">
Expand Down
24 changes: 24 additions & 0 deletions src/Opw.PineBlog.RazorPages/Areas/Blog/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MediatR;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -15,6 +16,10 @@ public class IndexModel : PageModelBase<IndexModel>

public PostListModel PostList { get; set; }

public Models.MetadataModel Metadata { get; set; }

public Models.PageCoverModel PageCover { get; set; }

[ViewData]
public string Title { get; private set; }

Expand All @@ -31,6 +36,25 @@ public async Task<IActionResult> OnGetAsync(CancellationToken cancellationToken,
PostList = result.Value;
Title = result.Value.Blog.Title;

Metadata = new Models.MetadataModel
{
Description = PostList.Blog.Description,
Title = PostList.Blog.Title,
Type = "website",
Url = Request.GetEncodedUrl()
};

if (PostList.Blog.CoverUrl != null && !PostList.Blog.CoverUrl.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
Metadata.Image = $"{Request.Scheme}://{Request.Host}{PostList.Blog.CoverUrl}";

PageCover = new Models.PageCoverModel
{
Title = PostList.Blog.Title,
CoverUrl = PostList.Blog.CoverUrl,
CoverCaption = PostList.Blog.CoverCaption,
CoverLink = PostList.Blog.CoverLink
};

return Page();
}
}
Expand Down
11 changes: 3 additions & 8 deletions src/Opw.PineBlog.RazorPages/Areas/Blog/Pages/Post.cshtml
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
@page
@model PostModel
@{
ViewData["BlogTitle"] = Model.Post.Blog.Title;
var pageCoverModel = new Opw.PineBlog.RazorPages.Models.PageCoverModel(
Model.Post.Post.Title,
Model.Post.Post.CoverUrl,
Model.Post.Post.CoverCaption,
Model.Post.Post.CoverLink);
@section head {
<partial name="_Metadata" model="@Model.Metadata" />
}

<partial name="_PageCover" model="pageCoverModel" />
<partial name="_PageCover" model="@Model.PageCover" />

<div class="page-content">
<div class="container">
Expand Down
34 changes: 33 additions & 1 deletion src/Opw.PineBlog.RazorPages/Areas/Blog/Pages/Post.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Opw.PineBlog.Posts;

namespace Opw.PineBlog.RazorPages.Areas.Blog.Pages
Expand All @@ -14,6 +14,13 @@ public class PostModel : PageModelBase<PostModel>

public PineBlog.Models.PostModel Post { get; set; }

public Models.MetadataModel Metadata { get; set; }

public Models.PageCoverModel PageCover { get; set; }

[ViewData]
public string BlogTitle { get; set; }

[ViewData]
public string Title { get; private set; }

Expand All @@ -32,6 +39,31 @@ public async Task<IActionResult> OnGetAsync(string slug, CancellationToken cance
Post = result.Value;
Title = result.Value.Post.Title;

BlogTitle = Post.Blog.Title;

Metadata = new Models.MetadataModel
{
Author = Post.Post.Author.DisplayName,
Description = Post.Post.Description,
Published = Post.Post.Published,
Title = Post.Post.Title,
Type = "article",
Url = Request.GetEncodedUrl()
};

if (Post.Post.CoverUrl != null && !Post.Post.CoverUrl.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
Metadata.Image = $"{Request.Scheme}://{Request.Host}{Post.Post.CoverUrl}";
if (!string.IsNullOrWhiteSpace(Post.Post.Categories))
Metadata.Keywords = Post.Post.Categories?.Split(',');

PageCover = new Models.PageCoverModel
{
Title = Post.Post.Title,
CoverUrl = Post.Post.CoverUrl,
CoverCaption = Post.Post.CoverCaption,
CoverLink = Post.Post.CoverLink
};

return Page();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@model Opw.PineBlog.RazorPages.Models.MetadataModel
@if (!string.IsNullOrWhiteSpace(Model.Author))
{
<meta name="author" content="@Model.Author">
}
@if (Model.Keywords.Any())
{
<meta name="keywords" content="@string.Join(",", Model.Keywords)">
}
@if (!string.IsNullOrWhiteSpace(Model.Description))
{
<meta name="Description" content="@Model.Description">
<meta property="og:description " content="@Model.Description" />
}
@if (!string.IsNullOrWhiteSpace(Model.Title))
{
<meta property="og:title" content="@Model.Title" />
}
@if (!string.IsNullOrWhiteSpace(Model.Type))
{
<meta property="og:type" content="@Model.Type" />
if (Model.Type == "article")
{
@if (Model.Published.HasValue)
{
<meta name="article:published_time" content="@Model.Published.Value.ToUtc()">
}
@if (!string.IsNullOrWhiteSpace(Model.Author))
{
<meta name="article:author" content="@Model.Author">
}
@foreach (var tag in Model.Keywords)
{
<meta name="article:tag" content="@tag">
}
}
}
@if (!string.IsNullOrWhiteSpace(Model.Url))
{
<meta property="og:url" content="@Model.Url" />
}
@if (!string.IsNullOrWhiteSpace(Model.Image))
{
<meta property="og:image" content="@Model.Image" />
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
<div class="post-meta">
<img class="post-meta-img" src="~/@Model.Author.Avatar" alt="@Model.Author.DisplayName" />
<span class="post-meta-author">@Model.Author.DisplayName</span>
<time class="post-meta-time">@Model.Published.Value.ToFriendlyDateString()</time>
@if (Model.Published.HasValue)
{
<time class="post-meta-time" datetime="@Model.Published.Value.ToUtc()">@Model.Published.Value.ToFriendlyDateString()</time>
}
@if (!string.IsNullOrEmpty(Model.Categories))
{
<span>/</span>
Expand Down
51 changes: 51 additions & 0 deletions src/Opw.PineBlog.RazorPages/Models/MetadataModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;

namespace Opw.PineBlog.RazorPages.Models
{
/// <summary>
/// Model for the _Metadata partial view.
/// </summary>
public class MetadataModel
{
/// <summary>
/// The title of your object as it should appear within the graph, e.g., "The Rock".
/// </summary>
public string Title { get; set; }

/// <summary>
/// The description of the page.
/// </summary>
public string Description { get; set; }

/// <summary>
/// The keywords for search engines.
/// </summary>
public IEnumerable<string> Keywords { get; set; } = new List<string>();

/// <summary>
/// The published date, when Type is "article".
/// </summary>
public DateTime? Published { get; set; }

/// <summary>
/// The author of the page.
/// </summary>
public string Author { get; set; }

/// <summary>
/// The type of your object, e.g., "video.movie".
/// </summary>
public string Type { get; set; }

/// <summary>
/// An image URL which should represent your object within the graph.
/// </summary>
public string Image { get; set; }

/// <summary>
/// The canonical URL of your object that will be used as its permanent ID in the graph, e.g., "http://www.imdb.com/title/tt0117500/".
/// </summary>
public string Url { get; set; }
}
}
19 changes: 0 additions & 19 deletions src/Opw.PineBlog.RazorPages/Models/PageCoverModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,5 @@ public class PageCoverModel
/// Category filter.
/// </summary>
public string Category { get; set; }

/// <summary>
/// Implementation of PageCoverModel.
/// </summary>
/// <param name="title">The page title.</param>
/// <param name="coverUrl">Cover URL.</param>
/// <param name="coverCaption">Cover caption.</param>
/// <param name="coverLink">Cover link.</param>
/// <param name="postListType">Post list type.</param>
/// <param name="category">Category filter.</param>
public PageCoverModel(string title, string coverUrl, string coverCaption, string coverLink, PostListType postListType = PostListType.NotSet, string category = null)
{
Title = title;
CoverUrl = coverUrl;
CoverCaption = coverCaption;
CoverLink = coverLink;
PostListType = postListType;
Category = category;
}
}
}
5 changes: 5 additions & 0 deletions src/Opw/DateTimeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace Opw
{
public static class DateTimeExtensions
{
public static string ToUtc(this DateTime dateTime)
{
return dateTime.ToString("yyyy-MM-ddTHH:mm:sszzz");
}

public static string ToFriendlyDateTimeString(this DateTime Date)
{
return FriendlyDate(Date) + " @ " + Date.ToString("t").ToLower();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public async Task OnGetAsync_Should_SetPostListModel()
var mediaterMock = new Mock<IMediator>();
mediaterMock.Setup(m => m.Send(It.IsAny<IRequest<Result<PostListModel>>>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<PostListModel>.Success(new PostListModel {
Blog = new BlogModel(new PineBlogOptions()) { Title = "Blog Title" },
Blog = new BlogModel(new PineBlogOptions { Title = "Blog title", Description = "Blog description" }),
Pager = new Pager(0),
Posts = new List<Post>()
}));
Expand All @@ -46,6 +46,14 @@ public async Task OnGetAsync_Should_SetPostListModel()
pageModel.PostList.Pager.Should().NotBeNull();
pageModel.PostList.Posts.Should().NotBeNull();
pageModel.Title.Should().NotBeNull();


pageModel.PostList.Blog.Title.Should().Be("Blog title");
pageModel.PostList.Pager.Should().NotBeNull();
pageModel.PostList.Posts.Should().NotBeNull();
pageModel.Title.Should().Be("Blog title");
pageModel.Metadata.Description.Should().Be("Blog description");
pageModel.PageCover.Title.Should().Be("Blog title");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ public async Task OnGetAsync_Should_SetPostModel()
mediaterMock.Setup(m => m.Send(It.IsAny<IRequest<Result<PineBlog.Models.PostModel>>>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result<PineBlog.Models.PostModel>.Success(new PineBlog.Models.PostModel
{
Blog = new BlogModel(new PineBlogOptions()),
Post = new Post() { Title = "Post Title" }
Blog = new BlogModel(new PineBlogOptions { Title = "Blog title" }),
Post = new Post() {
Title = "Post title",
Description = "Post description",
Author = new Author { DisplayName = "Post author" }
}
}));

var httpContext = new DefaultHttpContext();
Expand All @@ -43,9 +47,14 @@ public async Task OnGetAsync_Should_SetPostModel()
var result = await pageModel.OnGetAsync("slug", default);

result.Should().BeOfType<PageResult>();
pageModel.Post.Blog.Should().NotBeNull();
pageModel.Post.Post.Should().NotBeNull();
pageModel.Title.Should().NotBeNull();
pageModel.Post.Blog.Title.Should().Be("Blog title");
pageModel.Post.Post.Title.Should().Be("Post title");
pageModel.Post.Post.Author.DisplayName.Should().Be("Post author");
pageModel.Title.Should().Be("Post title");
pageModel.Metadata.Description.Should().Be("Post description");
pageModel.Metadata.Author.Should().Be("Post author");
pageModel.PageCover.Title.Should().Be("Post title");
pageModel.BlogTitle.Should().Be("Blog title");
}

[Fact]
Expand Down

0 comments on commit 34686c4

Please sign in to comment.