moves notification logic to umbnotifications.directive instead of in main (not sure why it was there). Updates the AuthorizeUpgrade screen to be able to show YSOD or alert messages when there are server errors. Adds htmlhelper extensions to share between Default.cshtml and AuthorizeUpgrade.cshtml. Adds null check for BackOfficeUserManager.

This commit is contained in:
Shannon
2015-04-01 16:04:19 +11:00
parent d185f93c35
commit df6bb36876
14 changed files with 187 additions and 112 deletions

View File

@@ -3,7 +3,7 @@
* @name umbraco.directives.directive:umbNavigation
* @restrict E
**/
function leftColumnDirective() {
function umbNavigationDirective() {
return {
restrict: "E", // restrict to an element
replace: true, // replace the html element with the template
@@ -11,4 +11,4 @@ function leftColumnDirective() {
};
}
angular.module('umbraco.directives').directive("umbNavigation", leftColumnDirective);
angular.module('umbraco.directives').directive("umbNavigation", umbNavigationDirective);

View File

@@ -2,11 +2,22 @@
* @ngdoc directive
* @name umbraco.directives.directive:umbNotifications
*/
function notificationDirective() {
function notificationDirective(notificationsService) {
return {
restrict: "E", // restrict to an element
replace: true, // replace the html element with the template
templateUrl: 'views/directives/umb-notifications.html'
templateUrl: 'views/directives/umb-notifications.html',
link: function (scope, element, attr, ctrl) {
//subscribes to notifications in the notification service
scope.notifications = notificationsService.current;
scope.$watch('notificationsService.current', function (newVal, oldVal, scope) {
if (newVal) {
scope.notifications = newVal;
}
});
}
};
}

View File

@@ -508,7 +508,7 @@ angular.module('umbraco.services')
/**
* @ngdoc method
* @name umbraco.services.dialogService#ysodDialog
* @name umbraco.services.dialogService#embedDialog
* @methodOf umbraco.services.dialogService
* @description
* Opens a dialog to an embed dialog
@@ -531,7 +531,7 @@ angular.module('umbraco.services')
var newScope = $rootScope.$new();
newScope.error = ysodError;
return openDialog({
modalClass: "umb-modal wide",
modalClass: "umb-modal wide ysod",
scope: newScope,
//callback: options.callback,
template: 'views/common/dialogs/ysod.html',

View File

@@ -15,13 +15,7 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
$scope.authenticated = null;
$scope.avatar = "assets/img/application/logo.png";
$scope.touchDevice = appState.getGlobalState("touchDevice");
//subscribes to notifications in the notification service
$scope.notifications = notificationsService.current;
$scope.$watch('notificationsService.current', function (newVal, oldVal, scope) {
if (newVal) {
$scope.notifications = newVal;
}
});
$scope.removeNotification = function (index) {
notificationsService.remove(index);

View File

@@ -176,3 +176,12 @@ body {
.emptySection #contentwrapper {left: 80px;}
.emptySection #speechbubble {left: 0;}
.emptySection #navigation {display: none}
.login-only #speechbubble {
z-index: 10000;
left: 0 !important;
}
.login-only #speechbubble ul {
padding-left:20px
}

View File

@@ -193,3 +193,6 @@
height: 12px
}
.umb-modal.ysod {
z-index: 10000;
}

View File

@@ -1,4 +1,4 @@
<div class="umb-panel ysod" ng-controller="Umbraco.Dialogs.YsodController">
<div class="umb-panel" ng-controller="Umbraco.Dialogs.YsodController">
<div class="umb-panel-body with-footer no-header">

View File

@@ -1,14 +1,24 @@
@using System.Web.Mvc
@using System.Collections
@using System.Net.Http
@using System.Web.Mvc.Html
@using Umbraco.Core
@using ClientDependency.Core
@using ClientDependency.Core.Mvc
@using Microsoft.Owin.Security
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@using Umbraco.Core.IO
@using Umbraco.Web
@using Umbraco.Web.Editors
@using umbraco
@inherits System.Web.Mvc.WebViewPage
@{
Layout = null;
Html
.RequiresCss("assets/css/umbraco.css", "Umbraco")
.RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco")
.RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco");
}
<!DOCTYPE html>
@@ -17,10 +27,13 @@
<head>
<base href="@GlobalSettings.Path.EnsureEndsWith('/')" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Umbraco</title>
<link rel="stylesheet" href="assets/css/umbraco.css" />
@Html.RenderCssHere(
new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
new BasicPath("UmbracoClient", IOHelper.ResolveUrl(SystemDirectories.UmbracoClient)))
@*Because we're lazy loading angular js, the embedded cloak style will not be loaded initially, but we need it*@
<style>
@@ -30,28 +43,17 @@
</style>
</head>
<body id="umbracoMainPageBody" ng-controller="Umbraco.AuthorizeUpgradeController">
<body id="umbracoMainPageBody" ng-controller="Umbraco.AuthorizeUpgradeController" class="login-only">
<div data-backdrop="false" class="modal hide login-overlay" aria-hidden="false" style="display: block;">
<div ng-include="'views/common/dialogs/login.html'"></div>
</div>
@*
These are the bare minimal server variables that are required for the application to start without being authenticated,
we will load the rest of the server vars after the user is authenticated.
*@
<script type="text/javascript">
var Umbraco = {};
Umbraco.Sys = {};
Umbraco.Sys.ServerVariables = {
"umbracoUrls": {
"authenticationApiBaseUrl": "@(Url.GetUmbracoApiServiceBaseUrl<AuthenticationController>(controller => controller.PostLogin(null)))",
"serverVarsJs": '@Url.Action("ServerVariables", "BackOffice")'
}
};
</script>
<umb-notifications></umb-notifications>
@Html.BareMinimumServerVariables(Url, (string)ViewBag.UmbracoPath)
@Html.AngularExternalLoginInfoValues((IEnumerable<string>)ViewBag.ExternalSignInError)
@*And finally we can load in our angular app*@
<script type="text/javascript" src="lib/rgrove-lazyload/lazyload.js"></script>
@@ -59,4 +61,3 @@
</body>
</html>

View File

@@ -14,6 +14,24 @@
@inherits System.Web.Mvc.WebViewPage
@{
var isDebug = false;
if (Request.RawUrl.IndexOf('?') >= 0)
{
var parsed = HttpUtility.ParseQueryString(Request.RawUrl.Split('?')[1]);
var attempt = parsed["umbDebug"].TryConvertTo<bool>();
if (attempt && attempt.Result)
{
isDebug = true;
}
}
Html
.RequiresCss("assets/css/umbraco.css", "Umbraco")
.RequiresCss("tree/treeicons.css", "UmbracoClient")
.RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco")
.RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco");
}
<!DOCTYPE html>
@@ -28,13 +46,6 @@
<title ng-bind="$root.locationTitle">Umbraco</title>
@{
Html
.RequiresCss("assets/css/umbraco.css", "Umbraco")
.RequiresCss("tree/treeicons.css", "UmbracoClient")
.RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco")
.RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco");
}
@Html.RenderCssHere(
new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
new BasicPath("UmbracoClient", IOHelper.ResolveUrl(SystemDirectories.UmbracoClient)))
@@ -55,77 +66,14 @@
<umb-notifications></umb-notifications>
@Html.BareMinimumServerVariables(Url, (string)ViewBag.UmbracoPath)
@{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes()
.Where(p => p.Properties.ContainsKey("UmbracoBackOffice"))
.Select(p => new
{
authType = p.AuthenticationType,
caption = p.Caption,
properties = p.Properties
})
.ToArray();
}
@*
These are the bare minimal server variables that are required for the application to start without being authenticated,
we will load the rest of the server vars after the user is authenticated.
*@
<script type="text/javascript">
var Umbraco = {};
Umbraco.Sys = {};
Umbraco.Sys.ServerVariables = {
"umbracoUrls": {
"authenticationApiBaseUrl": "@(Url.GetUmbracoApiServiceBaseUrl<AuthenticationController>(controller => controller.PostLogin(null)))",
"serverVarsJs": "@Url.GetUrlWithCacheBust("ServerVariables", "BackOffice")",
"externalLoginsUrl": "@(Url.Action("ExternalLogin", "BackOffice", new {area = ViewBag.UmbracoPath}))"
},
"application": {
"applicationPath" : "@Context.Request.ApplicationPath"
}
};
</script>
<script>
//define a callback that is executed when we bootstrap angular, this is used to inject angular values
//with server side info
document.angularReady = function(app) {
//add external login values
var errors = [];
@if (ViewBag.ExternalSignInError != null)
{
foreach (var error in ViewBag.ExternalSignInError)
{
<text>errors.push("@error");</text>
}
}
app.value("externalLoginInfo", {
errors: errors,
providers: @Html.Raw(JsonConvert.SerializeObject(loginProviders))
});
}
</script>
@Html.AngularExternalLoginInfoValues((IEnumerable<string>)ViewBag.ExternalSignInError)
@*And finally we can load in our angular app*@
<script type="text/javascript" src="lib/rgrove-lazyload/lazyload.js"></script>
<script type="text/javascript" src="@Url.GetUrlWithCacheBust("Application", "BackOffice")"></script>
@{
var isDebug = false;
if (Request.RawUrl.IndexOf('?') >= 0)
{
var parsed = HttpUtility.ParseQueryString(Request.RawUrl.Split('?')[1]);
var attempt = parsed["umbDebug"].TryConvertTo<bool>();
if (attempt && attempt.Result)
{
isDebug = true;
}
}
}
@if (isDebug)
{
@Html.RenderProfiler()

View File

@@ -49,7 +49,19 @@ namespace Umbraco.Web.Editors
protected BackOfficeUserManager UserManager
{
get { return _userManager ?? (_userManager = TryGetOwinContext().Result.GetUserManager<BackOfficeUserManager>()); }
get
{
if (_userManager == null)
{
var mgr = TryGetOwinContext().Result.GetUserManager<BackOfficeUserManager>();
if (mgr == null)
{
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeUserManager) + " from the " + typeof(IOwinContext) + " GetUserManager method");
}
_userManager = mgr;
}
return _userManager;
}
}
/// <summary>

View File

@@ -94,6 +94,8 @@ namespace Umbraco.Web.Editors
[HttpGet]
public ActionResult AuthorizeUpgrade()
{
ViewBag.UmbracoPath = GlobalSettings.UmbracoMvcArea;
return View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml");
}

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Microsoft.Owin.Security;
using Newtonsoft.Json;
using Umbraco.Web.Editors;
namespace Umbraco.Web
{
/// <summary>
/// HtmlHelper extensions for the back office
/// </summary>
public static class HtmlHelperBackOfficeExtensions
{
/// <summary>
/// Outputs a script tag containing the bare minimum (non secure) server vars for use with the angular app
/// </summary>
/// <param name="html"></param>
/// <param name="uri"></param>
/// <param name="umbracoPath"></param>
/// <returns></returns>
/// <remarks>
/// These are the bare minimal server variables that are required for the application to start without being authenticated,
/// we will load the rest of the server vars after the user is authenticated.
/// </remarks>
public static IHtmlString BareMinimumServerVariables(this HtmlHelper html, UrlHelper uri, string umbracoPath)
{
var str = @"<script type=""text/javascript"">
var Umbraco = {};
Umbraco.Sys = {};
Umbraco.Sys.ServerVariables = {
""umbracoUrls"": {
""authenticationApiBaseUrl"": """ + uri.GetUmbracoApiServiceBaseUrl<AuthenticationController>(controller => controller.PostLogin(null)) + @""",
""serverVarsJs"": """ + uri.GetUrlWithCacheBust("ServerVariables", "BackOffice") + @""",
""externalLoginsUrl"": """ + uri.Action("ExternalLogin", "BackOffice", new {area = umbracoPath}) + @"""
},
""application"": {
""applicationPath"": """ + html.ViewContext.HttpContext.Request.ApplicationPath + @"""
},
//""isDebuggingEnabled"" : " + html.ViewContext.HttpContext.IsDebuggingEnabled.ToString().ToLowerInvariant() + @"
""isDebuggingEnabled"" : false
};
</script>";
return html.Raw(str);
}
/// <summary>
/// Used to render the script tag that will pass in the angular externalLoginInfo service on page load
/// </summary>
/// <param name="html"></param>
/// <param name="externalLoginErrors"></param>
/// <returns></returns>
public static IHtmlString AngularExternalLoginInfoValues(this HtmlHelper html, IEnumerable<string> externalLoginErrors)
{
var loginProviders = html.ViewContext.HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes()
.Where(p => p.Properties.ContainsKey("UmbracoBackOffice"))
.Select(p => new
{
authType = p.AuthenticationType,
caption = p.Caption,
properties = p.Properties
})
.ToArray();
//define a callback that is executed when we bootstrap angular, this is used to inject angular values
//with server side info
var sb = new StringBuilder(@"<script type=""text/javascript"">");
sb.AppendLine(@"document.angularReady = function(app) {");
sb.AppendLine(@"var errors = [];");
if (externalLoginErrors != null)
{
foreach (var error in externalLoginErrors)
{
sb.AppendFormat(@"errors.push(""{0}"");", error).AppendLine();
}
}
sb.AppendLine(@"app.value(""externalLoginInfo"", {");
sb.AppendLine(@"errors: errors,");
sb.Append(@"providers: ");
sb.AppendLine(JsonConvert.SerializeObject(loginProviders));
sb.AppendLine(@"});");
sb.AppendLine(@"}");
sb.AppendLine("</script>");
return html.Raw(sb.ToString());
}
}
}

View File

@@ -18,7 +18,6 @@ using umbraco.cms.businesslogic.member;
namespace Umbraco.Web
{
/// <summary>
/// HtmlHelper extensions for use in templates
/// </summary>

View File

@@ -308,6 +308,7 @@
</Compile>
<Compile Include="ApplicationContextExtensions.cs" />
<Compile Include="AreaRegistrationContextExtensions.cs" />
<Compile Include="HtmlHelperBackOfficeExtensions.cs" />
<Compile Include="UmbracoDefaultOwinStartup.cs" />
<Compile Include="IUmbracoContextAccessor.cs" />
<Compile Include="Models\ContentEditing\Relation.cs" />