Blogging module gravatar

pull/441/head
Yunus Emre Kalkan 7 years ago
parent 1d321a3856
commit 66bf128f18

@ -0,0 +1,210 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Blogging.Areas.Blog.Helpers.TagHelpers
{
/// <inheritdoc />
/// <summary>
/// Returns a Globally Recognised Avatar https://en.gravatar.com
/// </summary>
[HtmlTargetElement("img", Attributes = "gravatar-email")]
public class GravatarTagHelper : TagHelper
{
private readonly IHttpContextAccessor _contextAccessor;
public GravatarTagHelper(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
/// <summary>
/// Email Address for the Gravatar
/// </summary>
[HtmlAttributeName("gravatar-email")]
public string Email { get; set; }
/// <summary>
/// Gravatar content rating (note that Gravatars are self-rated)
/// </summary>
[HtmlAttributeName("gravatar-rating")]
public GravatarRating Rating { get; set; } = GravatarRating.GeneralAudiences;
/// <summary>
/// Size in pixels (default: 80)
/// </summary>
[HtmlAttributeName("gravatar-size")]
public int Size { get; set; } = 80;
/// <summary>
/// URL to a custom default image (e.g: 'Url.Content("~/images/no-grvatar.png")' )
/// </summary>
[HtmlAttributeName("default-image-url")]
public string DefaultImageUrl { get; set; } = "";
/// <summary>
/// Prefer the default image over the users own Gravatar
/// </summary>
[HtmlAttributeName("force-default-image")]
public bool ForceDefaultImage { get; set; }
/// <summary>
/// Default image if user hasn't created a Gravatar
/// </summary>
[HtmlAttributeName("default-image")]
public GravatarDefaultImage DefaultImage { get; set; } = GravatarDefaultImage.Default;
/// <summary>
/// Always do secure (https) requests
/// </summary>
[HtmlAttributeName("force-secure-request")]
public bool ForceSecureRequest { get; set; } = true;
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var emailAddress = Email == null ? string.Empty : Email.Trim().ToLower();
var url = string.Format("{0}://{1}.gravatar.com/avatar/{2}?s={3}{4}{5}{6}",
GetUrlScheme(),
GetUrlPrefix(),
GetMd5Hash(emailAddress),
Size,
GetDefaultImageParameter(),
GetForceDefaultImageParameter(),
GetRatingParameter()
);
output.Attributes.SetAttribute("src", url);
}
private string GetUrlScheme()
{
return ForceSecureRequest || _contextAccessor.HttpContext.Request.IsHttps
? "https" : "http";
}
private string GetUrlPrefix()
{
return ForceSecureRequest || _contextAccessor.HttpContext.Request.IsHttps ? "secure" : "www";
}
private string GetDefaultImageParameter()
{
return "&d=" + (!string.IsNullOrEmpty(DefaultImageUrl)
? System.Net.WebUtility.UrlEncode(DefaultImageUrl)
: GetEnumDescription(DefaultImage));
}
private string GetForceDefaultImageParameter()
{
return ForceDefaultImage ? "&f=y" : "";
}
private string GetRatingParameter()
{
return "&r=" + GetEnumDescription(Rating);
}
/// <summary>
/// Generates an MD5 hash of the given string
/// </summary>
/// <remarks>Source: http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx </remarks>
private static string GetMd5Hash(string input)
{
// Convert the input string to a byte array and compute the hash.
var data = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
var sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
foreach (var t in data)
{
sBuilder.Append(t.ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
/// <summary>
/// Returns the value of a Description for a given Enum value
/// </summary>
/// <remarks>Source: http://blogs.msdn.com/b/abhinaba/archive/2005/10/21/483337.aspx </remarks>
/// <param name="en"></param>
/// <returns></returns>
private static string GetEnumDescription(Enum en)
{
var type = en.GetType();
var memInfo = type.GetMember(en.ToString());
if (memInfo == null || memInfo.Length <= 0)
{
return en.ToString();
}
var attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Any())
{
return ((DescriptionAttribute)attrs.First()).Description;
}
return en.ToString();
}
public enum GravatarDefaultImage
{
/// <summary>Default Gravatar logo</summary>
[Description("")]
Default,
/// <summary>404 - do not load any image if none is associated with the email hash, instead return an HTTP 404 (File Not Found) response</summary>
[Description("404")]
Http404,
/// <summary>Mystery-Man - a simple, cartoon-style silhouetted outline of a person (does not vary by email hash)</summary>
[Description("mm")]
MysteryMan,
/// <summary>Identicon - a geometric pattern based on an email hash</summary>
[Description("identicon")]
Identicon,
/// <summary>MonsterId - a generated 'monster' with different colors, faces, etc</summary>
[Description("monsterid")]
MonsterId,
/// <summary>Wavatar - generated faces with differing features and backgrounds</summary>
[Description("wavatar")]
Wavatar,
/// <summary>Retro - awesome generated, 8-bit arcade-style pixelated faces</summary>
[Description("retro")]
Retro
}
/// <summary>
/// Gravatar allows users to self-rate their images so that they can indicate if an image is appropriate for a certain audience. By default, only 'G' rated images are displayed unless you indicate that you would like to see higher ratings
/// </summary>
public enum GravatarRating
{
/// <summary>Suitable for display on all websites with any audience type</summary>
[Description("g")]
GeneralAudiences,
/// <summary>May contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence</summary>
[Description("pg")]
ParentalGuidance,
/// <summary>May contain such things as harsh profanity, intense violence, nudity, or hard drug use</summary>
[Description("r")]
Restricted,
/// <summary>May contain hardcore sexual imagery or extremely disturbing violence</summary>
[Description("x")]
OnlyMature
}
}
}

@ -4,6 +4,7 @@
@using Microsoft.AspNetCore.Http.Extensions
@using Volo.Blogging
@using Volo.Blogging.Pages.Blog.Posts
@using Volo.Blogging.Areas.Blog.Helpers.TagHelpers
@inject IAuthorizationService Authorization
@model DetailModel
@{
@ -36,9 +37,6 @@
<div class="article-infos">
<div class="user-card">
<a>
<img src="https://placeimg.com/60/60/people" class="article-avatar">
</a>
<a >
<strong> @(Model.Post.Writer == null ? "" : Model.Post.Writer.UserName)</strong>, @ConvertDatetimeToTimeAgo(Model.Post.CreationTime)
</a>
<span class="seperator">|</span>
@ -46,7 +44,7 @@
<i class="fa fa-eye"></i> @L["ReadWithCount", @Model.Post.ReadCount]
</a>
<span class="seperator">|</span>
<a >
<a>
<i class="fa fa-comment"></i> @L["CommentWithCount", @Model.CommentCount]
</a>
@ -96,14 +94,14 @@
}
</p>
<h1>
<a asp-page="./Detail" asp-route-postUrl="@Model.Post.Url" asp-route-blogShortName="@Model.BlogShortName">@Model.Post.Title</a>
<a asp-page="./Detail" asp-route-postUrl="@Model.Post.Url" asp-route-blogShortName="@Model.BlogShortName">@Model.Post.Title</a>
</h1>
</div>
<div class="article-owner">
<div class="article-infos">
<div class="user-card">
<a>
<img src="https://placeimg.com/60/60/people" class="article-avatar">
<img gravatar-email="@Model.Post.Writer.Email" default-image="Identicon" class="article-avatar" />
</a>
<a>
<strong> @(Model.Post.Writer == null ? "" : Model.Post.Writer.UserName)</strong>, @ConvertDatetimeToTimeAgo(Model.Post.CreationTime)
@ -186,7 +184,7 @@
@foreach (var commentWithRepliesDto in Model.CommentsWithReplies)
{
<div class="media">
<img class="d-flex mr-3 rounded-circle comment-avatar" src="https://placeimg.com/120/120/people" alt="">
<img gravatar-email="@commentWithRepliesDto.Comment.Writer.Email" default-image="Identicon" class="d-flex mr-3 rounded-circle comment-avatar" />
<div class="media-body">
<h5 class="comment-owner">
@(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName)
@ -263,7 +261,7 @@
@foreach (var reply in commentWithRepliesDto.Replies)
{
<div class="media">
<img class="d-flex mr-3 rounded-circle answer-avatar" src="https://placeimg.com/120/120/people?t=1535457179534" alt="">
<img gravatar-email="@reply.Writer.Email" default-image="Identicon" class="d-flex mr-3 rounded-circle comment-avatar" />
<div class="media-body">
<h5 class="comment-owner">
@(reply.Writer == null ? "" : reply.Writer.UserName)

@ -86,7 +86,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
public string GetTwitterShareUrl(string title, string url)
{
var readAtString = " | Read More At";
var readAtString = " | Read More At ";
var linkedAccounts = "" ;
var otherCharsLength = (readAtString + linkedAccounts).Length;

@ -90,7 +90,7 @@
<div class="article-infos">
<div class="user-card">
<a>
<img src="https://placeimg.com/120/120/people" class="article-avatar">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="article-avatar" />
</a>
<a>
<strong>@post.Writer.UserName</strong>, @ConvertDatetimeToTimeAgo(post.CreationTime)
@ -189,7 +189,7 @@
<div class="article-infos">
<div class="user-card">
<a>
<img src="https://placeimg.com/120/120/pople" class="article-avatar">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="article-avatar" />
</a>
<a>
<strong>@post.Writer.UserName</strong>, @ConvertDatetimeToTimeAgo(post.CreationTime)

@ -1,3 +1,4 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Blogging.Web

@ -1,12 +1,6 @@
using System;
using System.Linq;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
using Volo.Blogging.Comments;
using Volo.Blogging.Comments.Dtos;
using Volo.Blogging.Posts;
using Volo.Blogging.Tagging;
using Volo.Blogging.Tagging.Dtos;
using Xunit;

Loading…
Cancel
Save