-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from prjseal/feature/add-edit-link
Added edit link tag helper with readme description too
- Loading branch information
Showing
7 changed files
with
299 additions
and
1 deletion.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
Our.Umbraco.TagHelpers/Composing/BackofficeUserComposer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Our.Umbraco.TagHelpers.Services; | ||
using Umbraco.Cms.Core.Composing; | ||
using Umbraco.Cms.Core.DependencyInjection; | ||
|
||
namespace Our.Umbraco.TagHelpers.Composing | ||
{ | ||
public class CustomComposer : IComposer | ||
{ | ||
public void Compose(IUmbracoBuilder builder) | ||
{ | ||
builder.Services.AddScoped<IBackofficeUserAccessor, BackofficeUserAccessor>(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
using Microsoft.AspNetCore.Mvc.Rendering; | ||
using Microsoft.AspNetCore.Razor.TagHelpers; | ||
using Our.Umbraco.TagHelpers.Extensions; | ||
using Our.Umbraco.TagHelpers.Services; | ||
using System.Text; | ||
using Umbraco.Cms.Core.Web; | ||
|
||
namespace Our.Umbraco.TagHelpers | ||
{ | ||
/// <summary> | ||
/// If the user viewing the front end is logged in as an umbraco user | ||
/// then an edit link will display on the front end of the site. This will | ||
/// take you to the umbraco backoffice to edit the current page. | ||
/// </summary> | ||
[HtmlTargetElement("our-edit-link")] | ||
public class EditLinkTagHelper : TagHelper | ||
{ | ||
private readonly IBackofficeUserAccessor _backofficeUserAccessor; | ||
private IUmbracoContextAccessor _umbracoContextAccessor; | ||
|
||
public EditLinkTagHelper(IBackofficeUserAccessor backofficeUserAccessor, IUmbracoContextAccessor umbracoContextAccessor) | ||
{ | ||
_backofficeUserAccessor = backofficeUserAccessor; | ||
_umbracoContextAccessor = umbracoContextAccessor; | ||
} | ||
|
||
/// <summary> | ||
/// The id of the current content item | ||
/// </summary> | ||
[HtmlAttributeName("content-id")] | ||
public int ContentId { get; set; } = int.MinValue; | ||
|
||
/// <summary> | ||
/// Override the umbraco edit content url if yours is different | ||
/// </summary> | ||
[HtmlAttributeName("edit-url")] | ||
public string EditUrl { get; set; } = "/umbraco#/content/content/edit/"; | ||
|
||
/// <summary> | ||
/// A boolean to say whether or not you would like to use the default styling. | ||
/// </summary> | ||
[HtmlAttributeName("use-default-styles")] | ||
public bool UseDefaultStyles { get; set; } = false; | ||
|
||
public override void Process(TagHelperContext context, TagHelperOutput output) | ||
{ | ||
// Turn <our-edit-link> into an <a> tag | ||
output.TagName = "a"; | ||
|
||
// An outer wrapper div if we use inbuilt styling | ||
var outerDiv = new TagBuilder("div"); | ||
|
||
// Check if the user is logged in to the backoffice | ||
// and they have access to the content section | ||
if (_backofficeUserAccessor.BackofficeUser.IsAllowedToSeeEditLink()) | ||
{ | ||
// Try & get Umbraco Current Node int ID (Only do this if ContentId has NOT been set) | ||
if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext) && ContentId == int.MinValue) | ||
{ | ||
ContentId = umbracoContext.PublishedRequest.PublishedContent.Id; | ||
} | ||
|
||
// Backoffice URL to content item | ||
var editLinkUrl = $"{EditUrl}{ContentId}"; | ||
|
||
if (UseDefaultStyles) | ||
{ | ||
// Wrap the <a> in a <div> | ||
// Render the outer div with some inline styles | ||
outerDiv.Attributes.Add("style", GetOuterElementStyles()); | ||
output.PreElement.AppendHtml(outerDiv.RenderStartTag()); | ||
} | ||
|
||
// Set the link on the <a> tag | ||
output.Attributes.SetAttribute("href", editLinkUrl); | ||
|
||
if (UseDefaultStyles) | ||
{ | ||
output.Attributes.SetAttribute("style", GetLinkStyles()); | ||
} | ||
|
||
if (UseDefaultStyles) | ||
{ | ||
//Add the closing outer div | ||
output.PostElement.AppendHtml(outerDiv.RenderEndTag()); | ||
} | ||
|
||
return; | ||
} | ||
else | ||
{ | ||
output.SuppressOutput(); | ||
return; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Helper method to get the link styles | ||
/// </summary> | ||
/// <param name="linkColour">The CSS colour of the link text</param> | ||
/// <param name="linkBackgroundColour">The CSS colour of the link background</param> | ||
/// <param name="linkPadding">The padding around the link</param> | ||
/// <param name="fontSize">The font size of the link text</param> | ||
/// <param name="borderRadius">The border radius of the link</param> | ||
/// <returns></returns> | ||
private static string GetLinkStyles( | ||
string linkColour = "#ffffff", | ||
string linkBackgroundColour = "#1b264f", | ||
int linkPadding = 10, | ||
int fontSize = 16, | ||
int borderRadius = 6) | ||
{ | ||
StringBuilder linkStyles = new StringBuilder(); | ||
linkStyles.Append($"color:{linkColour};"); | ||
linkStyles.Append($"background-color:{linkBackgroundColour};"); | ||
linkStyles.Append($"padding:{linkPadding}px;"); | ||
linkStyles.Append($"font-size:{fontSize}px;"); | ||
linkStyles.Append($"border-radius:{borderRadius}px;"); | ||
return linkStyles.ToString(); | ||
} | ||
|
||
/// <summary> | ||
/// Helper method to get the outer element styles | ||
/// </summary> | ||
/// <param name="outerPosition">The CSS position of the outer element</param> | ||
/// <param name="margin">The margin around the outer element</param> | ||
/// <param name="zindex">The z-index of the outer element</param> | ||
/// <param name="linkPadding">The padding around the link</param> | ||
/// <returns></returns> | ||
private static string GetOuterElementStyles( | ||
string outerPosition = "fixed", | ||
int margin = 10, | ||
int zindex = 10000, | ||
int linkPadding = 10) | ||
{ | ||
linkPadding /= 2; | ||
|
||
var outerStyles = new StringBuilder(); | ||
|
||
outerStyles.Append("display:block;"); | ||
if (outerPosition == "fixed") | ||
{ | ||
outerStyles.Append($"bottom:{margin + linkPadding}px;"); | ||
outerStyles.Append($"left:{margin}px;"); | ||
} | ||
|
||
outerStyles.Append($"z-index:{zindex};"); | ||
outerStyles.Append($"position:{outerPosition};"); | ||
|
||
return outerStyles.ToString(); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
Our.Umbraco.TagHelpers/Extensions/ClaimsIdentityExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using Umbraco.Cms.Core; | ||
|
||
namespace Our.Umbraco.TagHelpers.Extensions | ||
{ | ||
public static class ClaimsIdentityExtensions | ||
{ | ||
public static bool IsAllowedToSeeEditLink(this ClaimsIdentity identity) | ||
{ | ||
return IsLoggedIntoUmbraco(identity) && HasAccessToContentSection(identity); | ||
} | ||
|
||
public static bool IsLoggedIntoUmbraco(this ClaimsIdentity identity) | ||
{ | ||
return identity?.AuthenticationType != null | ||
&& identity.AuthenticationType == Constants.Security.BackOfficeAuthenticationType; | ||
} | ||
|
||
public static bool HasAccessToContentSection(this ClaimsIdentity identity) | ||
{ | ||
return identity?.Claims != null && identity.Claims.Any(x => | ||
x.Type == Constants.Security.AllowedApplicationsClaimType | ||
&& x.Value == Constants.Conventions.PermissionCategories.ContentCategory); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authentication.Cookies; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Options; | ||
using System.Security.Claims; | ||
using Umbraco.Extensions; | ||
|
||
namespace Our.Umbraco.TagHelpers.Services | ||
{ | ||
|
||
/// <summary> | ||
/// Gets the backoffice user from the cookie | ||
/// Code from Markus Johansson on our.umbraco.com | ||
/// https://our.umbraco.com/forum/umbraco-9/106857-how-do-i-determine-if-a-backoffice-user-is-logged-in-from-a-razor-view#comment-334423 | ||
/// </summary> | ||
public class BackofficeUserAccessor : IBackofficeUserAccessor | ||
{ | ||
private readonly IOptionsSnapshot<CookieAuthenticationOptions> _cookieOptionsSnapshot; | ||
private readonly IHttpContextAccessor _httpContextAccessor; | ||
|
||
public BackofficeUserAccessor( | ||
IOptionsSnapshot<CookieAuthenticationOptions> cookieOptionsSnapshot, | ||
IHttpContextAccessor httpContextAccessor) | ||
{ | ||
_cookieOptionsSnapshot = cookieOptionsSnapshot; | ||
_httpContextAccessor = httpContextAccessor; | ||
} | ||
|
||
public ClaimsIdentity BackofficeUser | ||
{ | ||
get | ||
{ | ||
var httpContext = _httpContextAccessor.HttpContext; | ||
|
||
if (httpContext == null) | ||
return new ClaimsIdentity(); | ||
|
||
CookieAuthenticationOptions cookieOptions = _cookieOptionsSnapshot.Get(global::Umbraco.Cms.Core.Constants.Security.BackOfficeAuthenticationType); | ||
string backOfficeCookie = httpContext.Request.Cookies[cookieOptions.Cookie.Name!]; | ||
|
||
if (string.IsNullOrEmpty(backOfficeCookie)) | ||
return new ClaimsIdentity(); | ||
|
||
AuthenticationTicket unprotected = cookieOptions.TicketDataFormat.Unprotect(backOfficeCookie!); | ||
ClaimsIdentity backOfficeIdentity = unprotected!.Principal.GetUmbracoIdentity(); | ||
|
||
return backOfficeIdentity; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using System.Security.Claims; | ||
|
||
namespace Our.Umbraco.TagHelpers.Services | ||
{ | ||
public interface IBackofficeUserAccessor | ||
{ | ||
ClaimsIdentity BackofficeUser { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters