diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 2efd21de94..f891dc83cf 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -1938,6 +1938,7 @@
+
Web.Template.config
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index f76066da34..333aa63b64 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -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(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(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("You have been invited to the Umbraco Back Office!
{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"
+ });
+ }
+
}
///
diff --git a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
index f3bcb80005..de74acffe3 100644
--- a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
@@ -22,5 +22,6 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "message", IsRequired = true)]
[Required]
public string Message { get; set; }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/ContentEditing/UserInviteEmail.cs b/src/Umbraco.Web/Models/ContentEditing/UserInviteEmail.cs
new file mode 100644
index 0000000000..f0cc1c1879
--- /dev/null
+++ b/src/Umbraco.Web/Models/ContentEditing/UserInviteEmail.cs
@@ -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 UserGroups { get; set; }
+
+ public IEnumerable StartContentIds { get; set; }
+
+ public IEnumerable StartMediaIds { get; set; }
+
+ public string InviteUrl { get; set; }
+
+ public string Message { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Mvc/ControllerExtensions.cs b/src/Umbraco.Web/Mvc/ControllerExtensions.cs
index 734e60e8f5..9e55745002 100644
--- a/src/Umbraco.Web/Mvc/ControllerExtensions.cs
+++ b/src/Umbraco.Web/Mvc/ControllerExtensions.cs
@@ -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();
}
}
+ ///
+ /// Renders the partial view to string.
+ ///
+ /// The request context.
+ ///
+ ///
+ /// Name of the view.
+ /// The model.
+ /// true if it is a Partial view, otherwise false for a normal view
+ ///
+ 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() { } }
+
///
/// 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
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 4ba6564409..6631c5be02 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -391,6 +391,7 @@
+