Gets email sending using razor view

This commit is contained in:
Shannon
2017-06-14 11:29:15 +02:00
parent e757868d09
commit cd1e88d151
6 changed files with 130 additions and 11 deletions

View File

@@ -1938,6 +1938,7 @@
<Content Include="Views\Partials\Grid\Editors\Base.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" />
<Content Include="Umbraco\Views\UserInvite.cshtml" />
<None Include="Web.Debug.config.transformed" />
<None Include="web.Template.Debug.config">
<DependentUpon>Web.Template.config</DependentUpon>

View File

@@ -7,6 +7,9 @@ using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.WebPages;
using AutoMapper;
using ClientDependency.Core;
using Microsoft.AspNet.Identity;
@@ -25,6 +28,7 @@ using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using IUser = Umbraco.Core.Models.Membership.IUser;
using Task = System.Threading.Tasks.Task;
namespace Umbraco.Web.Editors
{
@@ -281,22 +285,61 @@ namespace Umbraco.Web.Editors
Services.UserService.Save(user);
var display = Mapper.Map<UserDisplay>(user);
await SendEmailAsync(display, Security.CurrentUser.Name, userSave.Message);
return display;
}
private async Task SendEmailAsync(UserDisplay userDisplay, string from, string message)
{
//now send the email
var token = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var token = await UserManager.GenerateEmailConfirmationTokenAsync((int)userDisplay.Id);
var link = string.Format("{0}#/login/false?invite={1}{2}{3}",
ApplicationContext.UmbracoApplicationUrl,
user.Id,
(int)userDisplay.Id,
WebUtility.UrlEncode("|"),
token.ToUrlBase64());
await UserManager.EmailService.SendAsync(new IdentityMessage
{
Body = string.Format("You have been invited to the Umbraco Back Office!\n\n{0}\n\nClick this link to accept the invite\n\n{1}", userSave.Message, link),
Destination = userSave.Email,
Subject = "You have been invited to the Umbraco Back Office!"
});
var virtualPath = SystemDirectories.Umbraco.EnsureEndsWith("/") + "Views/UserInvite.cshtml";
var view = IOHelper.MapPath(virtualPath);
return Mapper.Map<UserDisplay>(user);
//This should always exist but just in case, we'll check
if (System.IO.File.Exists(view) == false)
{
await UserManager.EmailService.SendAsync(new IdentityMessage
{
Body = string.Format("<html><body>You have been invited to the Umbraco Back Office!<br/><br/>{0}\n\nClick this link to accept the invite\n\n{1}", message, link),
Destination = userDisplay.Email,
Subject = "You have been invited to the Umbraco Back Office"
});
}
else
{
//TODO: Inject IControllerFactory in v8
var httpContext = TryGetHttpContext().Result;
var requestContext = new RequestContext(httpContext, new RouteData());
var userInviteEmail = new UserInviteEmail
{
StartContentIds = userDisplay.StartContentIds,
StartMediaIds = userDisplay.StartMediaIds,
Email = userDisplay.Email,
Name = userDisplay.Name,
UserGroups = userDisplay.UserGroups,
Message = message,
InviteUrl = link,
FromName = from
};
var viewResult = requestContext.RenderViewToString(new ViewDataDictionary(), new TempDataDictionary(), virtualPath, userInviteEmail, false);
await UserManager.EmailService.SendAsync(new IdentityMessage
{
Body = viewResult,
Destination = userDisplay.Email,
Subject = "You have been invited to the Umbraco Back Office"
});
}
}
/// <summary>

View File

@@ -22,5 +22,6 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "message", IsRequired = true)]
[Required]
public string Message { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace Umbraco.Web.Models.ContentEditing
{
public class UserInviteEmail
{
public string Name { get; set; }
public string FromName { get; set; }
public string Email { get; set; }
public IEnumerable<UserGroupBasic> UserGroups { get; set; }
public IEnumerable<EntityBasic> StartContentIds { get; set; }
public IEnumerable<EntityBasic> StartMediaIds { get; set; }
public string InviteUrl { get; set; }
public string Message { get; set; }
}
}

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Threading;
using System.Web.Mvc;
using System.Web.Routing;
namespace Umbraco.Web.Mvc
{
@@ -101,16 +102,65 @@ namespace Umbraco.Web.Mvc
using (var sw = new StringWriter())
{
var viewResult = !isPartial
var viewResult = isPartial == false
? ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null)
: ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
if (viewResult.View == null)
throw new InvalidOperationException("No view could be found by name " + viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
/// <summary>
/// Renders the partial view to string.
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <param name="viewData"></param>
/// <param name="tempData"></param>
/// <param name="viewName">Name of the view.</param>
/// <param name="model">The model.</param>
/// <param name="isPartial">true if it is a Partial view, otherwise false for a normal view </param>
/// <returns></returns>
internal static string RenderViewToString(
this RequestContext requestContext,
ViewDataDictionary viewData,
TempDataDictionary tempData,
string viewName, object model, bool isPartial = false)
{
if (requestContext == null) throw new ArgumentNullException("requestContext");
if (viewData == null) throw new ArgumentNullException("viewData");
if (tempData == null) throw new ArgumentNullException("tempData");
var routeData = requestContext.RouteData;
if (routeData.Values.ContainsKey("controller") == false)
routeData.Values.Add("controller", "Fake");
viewData.Model = model;
var controllerContext = new ControllerContext(
requestContext.HttpContext, routeData,
new FakeController
{
ViewData = viewData
});
using (var sw = new StringWriter())
{
var viewResult = isPartial == false
? ViewEngines.Engines.FindView(controllerContext, viewName, null)
: ViewEngines.Engines.FindPartialView(controllerContext, viewName);
if (viewResult.View == null)
throw new InvalidOperationException("No view could be found by name " + viewName);
var viewContext = new ViewContext(controllerContext, viewResult.View, viewData, tempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
private class FakeController : ControllerBase { protected override void ExecuteCore() { } }
/// <summary>
/// Normally in MVC the way that the View object gets assigned to the result is to Execute the ViewResult, this however
/// will write to the Response output stream which isn't what we want. Instead, this method will use the same logic inside

View File

@@ -391,6 +391,7 @@
<Compile Include="Models\ContentEditing\UserBasic.cs" />
<Compile Include="Models\ContentEditing\UserGroupBasic.cs" />
<Compile Include="Models\ContentEditing\UserGroupDisplay.cs" />
<Compile Include="Models\ContentEditing\UserInviteEmail.cs" />
<Compile Include="Models\DetachedPublishedContent.cs" />
<Compile Include="Models\DetachedPublishedProperty.cs" />
<Compile Include="Models\ContentEditing\UserInvite.cs" />