diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js
index 3ea6c46580..96ebf4f07b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js
@@ -26,6 +26,8 @@
vm.selectedBulkUserGroups = [];
+ vm.usernameIsEmail = Umbraco.Sys.ServerVariables.umbracoSettings.usernameIsEmail;
+
vm.allowDisableUser = true;
vm.allowEnableUser = true;
vm.allowUnlockUser = true;
@@ -50,24 +52,31 @@
"selected": true
};
- //don't set this if no email is configured
- if (Umbraco.Sys.ServerVariables.umbracoSettings.emailServerConfigured) {
+ //don't show the invite button if no email is configured
+ if (Umbraco.Sys.ServerVariables.umbracoSettings.showUserInvite) {
vm.defaultButton = {
labelKey: "user_inviteUser",
- handler: function () {
+ handler: function() {
vm.setUsersViewState('inviteUser');
}
};
+ vm.subButtons = [
+ {
+ labelKey: "user_createUser",
+ handler: function () {
+ vm.setUsersViewState('createUser');
+ }
+ }
+ ];
}
-
- vm.subButtons = [
- {
+ else {
+ vm.defaultButton = {
labelKey: "user_createUser",
handler: function () {
vm.setUsersViewState('createUser');
}
- }
- ];
+ };
+ }
vm.toggleFilter = toggleFilter;
vm.setUsersViewState = setUsersViewState;
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html
index 1d07e9db7e..e4fd2d24be 100644
--- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html
+++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html
@@ -325,6 +325,13 @@
+
+
+ Required
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js
index 0e06085ff4..024a014245 100644
--- a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js
+++ b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js
@@ -1,5 +1,7 @@
-module.exports = function(karma) {
- karma.configure({
+module.exports = function(config) {
+
+ config.set({
+
// base path, that will be used to resolve files and exclude
basePath: '../..',
@@ -7,31 +9,23 @@ module.exports = function(karma) {
// list of files / patterns to load in the browser
files: [
- 'lib/../build/belle/lib/jquery/jquery.min.js',
+
+ //libraries
+ 'lib-bower/jquery/jquery.min.js',
'lib/angular/1.1.5/angular.js',
'lib/angular/1.1.5/angular-cookies.min.js',
'lib/angular/1.1.5/angular-mocks.js',
'lib/angular/angular-ui-sortable.js',
-
- /*
- For angular 1.2:
- 'lib/angular/1.2/angular.js',
- 'lib/angular/1.2/angular-route.min.js',
- 'lib/angular/1.2/angular-touch.min.js',
- 'lib/angular/1.2/angular-cookies.min.js',
- 'lib/angular/1.2/angular-animate.min.js',
- 'lib/angular/1.2/angular-mocks.js',*/
-
-
- 'lib/../build/belle/lib/underscore/underscore-min.js',
- 'lib/../build/belle/lib/moment/moment-with-locales.js',
+ 'lib-bower/underscore/underscore-min.js',
+ 'lib-bower/moment/moment-with-locales.js',
'lib/umbraco/Extensions.js',
- 'lib/../build/belle/lib/rgrove-lazyload/lazyload.js',
- 'lib/../build/belle/lib/angular-local-storage/angular-local-storage.min.js',
+ 'lib-bower/rgrove-lazyload/lazyload.js',
+ 'lib-bower//angular-local-storage/angular-local-storage.min.js',
+ //app bootstrap and loader
'test/config/app.unit.js',
- 'src/common/mocks/umbraco.servervariables.js',
+ //application files
'src/common/directives/**/*.js',
'src/common/filters/*.js',
'src/common/services/*.js',
@@ -39,8 +33,9 @@ module.exports = function(karma) {
'src/common/resources/*.js',
'src/common/mocks/**/*.js',
'src/views/**/*.controller.js',
- 'test/unit/**/*.spec.js',
- {pattern: 'lib/**/*.js', watched: true, served: true, included: false}
+
+ //tests
+ 'test/unit/**/*.spec.js'
],
// list of files to exclude
@@ -66,7 +61,7 @@ module.exports = function(karma) {
// level of logging
// possible values: karma.LOG_DISABLE || karma.LOG_ERROR || karma.LOG_WARN || karma.LOG_INFO || karma.LOG_DEBUG
// CLI --log-level debug
- logLevel: karma.LOG_INFO,
+ logLevel: config.LOG_WARN,
// enable / disable watching file and executing tests whenever any file changes
// CLI --auto-watch --no-auto-watch
diff --git a/src/Umbraco.Web.UI/Umbraco/js/install.js b/src/Umbraco.Web.UI/Umbraco/js/install.js
deleted file mode 100644
index 41aab12c80..0000000000
--- a/src/Umbraco.Web.UI/Umbraco/js/install.js
+++ /dev/null
@@ -1,30 +0,0 @@
-yepnope({
-
- load: [
- 'lib/jquery/jquery-2.0.3.min.js',
-
- /* 1.1.5 */
- 'lib/angular/1.1.5/angular.min.js',
- 'lib/angular/1.1.5/angular-cookies.min.js',
- 'lib/angular/1.1.5/angular-mobile.min.js',
- 'lib/angular/1.1.5/angular-mocks.js',
- 'lib/angular/1.1.5/angular-sanitize.min.js',
- 'lib/underscore/underscore.js',
- 'js/umbraco.servervariables.js',
- 'js/app.dev.js'
- ],
-
- complete: function () {
- jQuery(document).ready(function () {
-
- angular.module('umbraco.install', [
- 'umbraco.resources',
- 'umbraco.services',
- 'umbraco.httpbackend',
- 'ngMobile'
- ]);
-
- angular.bootstrap(document, ['umbraco.install']);
- });
- }
-});
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap2.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap2.cshtml
index c8f9ab7cd1..8b189ae1a0 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap2.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap2.cshtml
@@ -2,10 +2,6 @@
@using Umbraco.Web.Templates
@using Newtonsoft.Json.Linq
-@*
- Razor helpers located at the bottom of this file
-*@
-
@if (Model != null && Model.sections != null)
{
var oneColumn = ((System.Collections.ICollection)Model.sections).Count == 1;
@@ -64,29 +60,21 @@
JObject cfg = contentItem.config;
if(cfg != null)
- foreach (JProperty property in cfg.Properties())
- {
- var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
- attrs.Add(property.Name + "=\"" + propertyValue + "\"");
+ foreach (JProperty property in cfg.Properties()) {
+ attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
}
-
+
JObject style = contentItem.styles;
- if (style != null) {
- var cssVals = new List();
- foreach (JProperty property in style.Properties())
- {
- var propertyValue = property.Value.ToString();
- if (string.IsNullOrWhiteSpace(propertyValue) == false)
- {
- cssVals.Add(property.Name + ":" + propertyValue + ";");
- }
- }
+ if (style != null) {
+ var cssVals = new List();
+ foreach (JProperty property in style.Properties())
+ cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
- if (cssVals.Any())
- attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\"");
+ if (cssVals.Any())
+ attrs.Add("style='" + string.Join(" ", cssVals) + "'");
}
-
+
return new MvcHtmlString(string.Join(" ", attrs));
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml
index 6ab5c1355a..e672aa2a11 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml
@@ -2,10 +2,6 @@
@using Umbraco.Web.Templates
@using Newtonsoft.Json.Linq
-@*
- Razor helpers located at the bottom of this file
-*@
-
@if (Model != null && Model.sections != null)
{
var oneColumn = ((System.Collections.ICollection)Model.sections).Count == 1;
@@ -64,29 +60,21 @@
JObject cfg = contentItem.config;
if(cfg != null)
- foreach (JProperty property in cfg.Properties())
- {
- var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
- attrs.Add(property.Name + "=\"" + propertyValue + "\"");
+ foreach (JProperty property in cfg.Properties()) {
+ attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
}
-
+
JObject style = contentItem.styles;
- if (style != null) {
- var cssVals = new List();
- foreach (JProperty property in style.Properties())
- {
- var propertyValue = property.Value.ToString();
- if (string.IsNullOrWhiteSpace(propertyValue) == false)
- {
- cssVals.Add(property.Name + ":" + propertyValue + ";");
- }
- }
+ if (style != null) {
+ var cssVals = new List();
+ foreach (JProperty property in style.Properties())
+ cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
- if (cssVals.Any())
- attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\"");
+ if (cssVals.Any())
+ attrs.Add("style='" + string.Join(" ", cssVals) + "'");
}
-
+
return new MvcHtmlString(string.Join(" ", attrs));
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml
index ffb7603048..a86c04819a 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml
@@ -1,4 +1,5 @@
@model dynamic
+@using Umbraco.Web.Templates
@functions {
public static string EditorView(dynamic contentItem)
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml
index c27be6bcdf..393157bcf8 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml
@@ -1,2 +1,7 @@
@model dynamic
-@Html.Raw(Model.value)
+@using Umbraco.Web.Templates
+
+
+
+ @Html.Raw(Model.value)
+
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml
index ed08bb2484..e0822808d8 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml
@@ -1,4 +1,6 @@
@inherits UmbracoViewPage
+@using Umbraco.Web.Templates
+
@if (Model.value != null)
{
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
index 5b5adbdc7d..09d04219f2 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
@@ -1,4 +1,5 @@
@model dynamic
+@using Umbraco.Web.Templates
@if (Model.value != null)
{
@@ -13,7 +14,7 @@
}
}
-
+
if (Model.value.caption != null)
{
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml
index 8c92ca0d83..0cac4eb1ff 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml
@@ -4,9 +4,8 @@
@if (Model.editor.config.markup != null)
{
string markup = Model.editor.config.markup.ToString();
- var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
-
- markup = markup.Replace("#value#", umbracoHelper.ReplaceLineBreaksForHtml(HttpUtility.HtmlEncode(Model.value.ToString())));
+
+ markup = markup.Replace("#value#", Model.value.ToString());
markup = markup.Replace("#style#", Model.editor.config.style.ToString());
diff --git a/src/Umbraco.Web.UI/config/grid.editors.config.js b/src/Umbraco.Web.UI/config/grid.editors.config.js
index b904920566..1adb6da2dc 100644
--- a/src/Umbraco.Web.UI/config/grid.editors.config.js
+++ b/src/Umbraco.Web.UI/config/grid.editors.config.js
@@ -1,4 +1,4 @@
-[
+[
{
"name": "Rich text editor",
"alias": "rte",
@@ -11,6 +11,40 @@
"view": "media",
"icon": "icon-picture"
},
+ {
+ "name": "Image wide",
+ "alias": "media_wide",
+ "view": "media",
+ "render": "/App_Plugins/Grid/Editors/Render/media_wide.cshtml",
+ "icon": "icon-picture"
+ },
+ {
+ "name": "Image wide cropped",
+ "alias": "media_wide_cropped",
+ "view": "media",
+ "render": "media",
+ "icon": "icon-picture",
+ "config": {
+ "size": {
+ "width": 1920,
+ "height": 700
+ }
+ }
+ },
+ {
+ "name": "Image rounded",
+ "alias": "media_round",
+ "view": "media",
+ "render": "/App_Plugins/Grid/Editors/Render/media_round.cshtml",
+ "icon": "icon-picture"
+ },
+ {
+ "name": "Image w/ text right",
+ "alias": "media_text_right",
+ "view": "/App_Plugins/Grid/Editors/Views/media_with_description.html",
+ "render": "/App_Plugins/Grid/Editors/Render/media_text_right.cshtml",
+ "icon": "icon-picture"
+ },
{
"name": "Macro",
"alias": "macro",
@@ -21,8 +55,29 @@
"name": "Embed",
"alias": "embed",
"view": "embed",
+ "render": "/App_Plugins/Grid/Editors/Render/embed_videowrapper.cshtml",
"icon": "icon-movie-alt"
},
+ {
+ "name": "Banner Headline",
+ "alias": "banner_headline",
+ "view": "textstring",
+ "icon": "icon-coin",
+ "config": {
+ "style": "font-size: 36px; line-height: 45px; font-weight: bold; text-align:center",
+ "markup": "#value#
"
+ }
+ },
+ {
+ "name": "Banner Tagline",
+ "alias": "banner_tagline",
+ "view": "textstring",
+ "icon": "icon-coin",
+ "config": {
+ "style": "font-size: 25px; line-height: 35px; font-weight: normal; text-align:center",
+ "markup": "#value#
"
+ }
+ },
{
"name": "Headline",
"alias": "headline",
@@ -32,6 +87,36 @@
"style": "font-size: 36px; line-height: 45px; font-weight: bold",
"markup": "#value#
"
}
+ },
+ {
+ "name": "Headline centered",
+ "alias": "headline_centered",
+ "view": "textstring",
+ "icon": "icon-coin",
+ "config": {
+ "style": "font-size: 30px; line-height: 45px; font-weight: bold; text-align:center;",
+ "markup": "#value#
"
+ }
+ },
+ {
+ "name": "Abstract",
+ "alias": "abstract",
+ "view": "textstring",
+ "icon": "icon-coin",
+ "config": {
+ "style": "font-size: 16px; line-height: 20px; font-weight: bold;",
+ "markup": "#value#
"
+ }
+ },
+ {
+ "name": "Paragraph",
+ "alias": "paragraph",
+ "view": "textstring",
+ "icon": "icon-font",
+ "config": {
+ "style": "font-size: 16px; line-height: 20px; font-weight: light;",
+ "markup": "#value#
"
+ }
},
{
"name": "Quote",
@@ -39,8 +124,28 @@
"view": "textstring",
"icon": "icon-quote",
"config": {
- "style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-style: italic; font-size: 18px",
+ "style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
"markup": "#value#
"
}
+ },
+ {
+ "name": "Quote with description",
+ "alias": "quote_D",
+ "view": "/App_Plugins/Grid/Editors/Views/quote_with_description.html",
+ "render": "/App_Plugins/Grid/Editors/Render/quote_with_description.cshtml",
+ "icon": "icon-quote",
+ "config": {
+ "style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px"
+ }
+ },
+ {
+ "name": "Code",
+ "alias": "code",
+ "view": "textstring",
+ "icon": "icon-code",
+ "config": {
+ "style": "overflow: auto;padding: 6px 10px;border: 1px solid #ddd;border-radius: 3px;background-color: #f8f8f8;font-size: .9rem;font-family: 'Courier 10 Pitch', Courier, monospace;line-height: 19px;",
+ "markup": "#value#
"
+ }
}
]
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
index 6687e71f4c..4e0c24434c 100644
--- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
+++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
@@ -66,6 +66,8 @@
false
+
+ true
false
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
index 5d0779f8b6..77615cf11a 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
@@ -81,14 +81,14 @@
Domain '%0%' has been updated
Edit Current Domains
-
Inherit
Culture
- or inherit culture from parent nodes. Will also apply
+ or inherit culture from parent nodes. Will also apply
to the current node, unless a domain below applies too.]]>
Domains
@@ -339,11 +339,11 @@
Number of columns
Number of rows
- Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates,
+ Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates,
by referring this ID using a <asp:content /> element.]]>
- Select a placeholder id from the list below. You can only
+ Select a placeholder id from the list below. You can only
choose Id's from the current template's master.]]>
Click on the image to see full size
@@ -380,15 +380,15 @@
- %0%' below
You can add additional languages under the 'languages' in the menu on the left
+ %0%' below
You can add additional languages under the 'languages' in the menu on the left
]]>
Culture Name
Edit the key of the dictionary item.
-
@@ -398,6 +398,8 @@
Confirm your password
Name the %0%...
Enter a name...
+ Enter an email...
+ Enter a username...
Label...
Enter a description...
Type to search...
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
index ed0edf8b6d..9f42eb7035 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
@@ -400,6 +400,7 @@
Name the %0%...
Enter a name...
Enter an email...
+ Enter a username...
Label...
Enter a description...
Type to search...
@@ -1661,6 +1662,7 @@ To manage your website, simply open the Umbraco back office and start adding con
User groups
has been invited
An invitation has been sent to the new user with details about how to log in to Umbraco.
+ Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar.
Writer
Translator
Change
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml
index de2c632b74..aa5e617cd1 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml
@@ -636,8 +636,12 @@
Återställ
+ Definiera beskräning
+ Ge beskärningen ett alias och dess standardbredd och -höjd
+ spara beskärning
+ Lägg till ny beskärning
-
+
Nuvarande version
Röd text kommer inte att synas i den valda versionen. , Grön betyder att den har tillkommit]]>
Dokumentet har återgått till en tidigare version
diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
index bfb1974f2f..27fbc6d5c5 100644
--- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
+++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
@@ -373,7 +373,7 @@ namespace Umbraco.Web.Cache
{
DistributedCache.Instance.RemoveUnpublishedPageCache(e.DeletedEntities.ToArray());
}
-
+
///
/// Handles cache refreshing for when content is saved (not published)
///
@@ -767,7 +767,6 @@ namespace Umbraco.Web.Cache
{
var handler = FindHandler(e);
if (handler == null) continue;
-
handler.Invoke(null, new[] { e.Sender, e.Args });
}
}
diff --git a/src/Umbraco.Web/Cache/PageCacheRefresher.cs b/src/Umbraco.Web/Cache/PageCacheRefresher.cs
index e884c9b3b8..d9bb7e9b88 100644
--- a/src/Umbraco.Web/Cache/PageCacheRefresher.cs
+++ b/src/Umbraco.Web/Cache/PageCacheRefresher.cs
@@ -50,8 +50,9 @@ namespace Umbraco.Web.Cache
///
public override void RefreshAll()
{
- content.Instance.RefreshContentFromDatabase();
- XmlPublishedContent.ClearRequest();
+ if (Suspendable.PageCacheRefresher.CanRefreshDocumentCacheFromDatabase)
+ content.Instance.RefreshContentFromDatabase();
+ ClearCaches();
base.RefreshAll();
}
@@ -61,11 +62,9 @@ namespace Umbraco.Web.Cache
/// The id.
public override void Refresh(int id)
{
- ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
- content.Instance.UpdateDocumentCache(id);
- XmlPublishedContent.ClearRequest();
- DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
- DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
+ if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
+ content.Instance.UpdateDocumentCache(id);
+ ClearCaches();
base.Refresh(id);
}
@@ -75,35 +74,35 @@ namespace Umbraco.Web.Cache
/// The id.
public override void Remove(int id)
{
- ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
- content.Instance.ClearDocumentCache(id, false);
- XmlPublishedContent.ClearRequest();
- DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
- DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
- ClearAllIsolatedCacheByEntityType();
+ if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
+ content.Instance.ClearDocumentCache(id, false);
+ ClearCaches();
base.Remove(id);
}
public override void Refresh(IContent instance)
{
- ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
- content.Instance.UpdateDocumentCache(new Document(instance));
- XmlPublishedContent.ClearRequest();
- DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
- DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
- ClearAllIsolatedCacheByEntityType();
+ if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
+ content.Instance.UpdateDocumentCache(new Document(instance));
+ ClearCaches();
base.Refresh(instance);
}
public override void Remove(IContent instance)
+ {
+ if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
+ content.Instance.ClearDocumentCache(new Document(instance), false);
+ ClearCaches();
+ base.Remove(instance);
+ }
+
+ private void ClearCaches()
{
ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
- content.Instance.ClearDocumentCache(new Document(instance), false);
XmlPublishedContent.ClearRequest();
DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
ClearAllIsolatedCacheByEntityType();
- base.Remove(instance);
}
}
}
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index ab41246753..3b185ef4b1 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -286,10 +286,11 @@ namespace Umbraco.Web.Editors
GetMaxRequestLength()
},
{"keepUserLoggedIn", UmbracoConfig.For.UmbracoSettings().Security.KeepUserLoggedIn},
+ {"usernameIsEmail", UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail},
{"cssPath", IOHelper.ResolveUrl(SystemDirectories.Css).TrimEnd('/')},
{"allowPasswordReset", UmbracoConfig.For.UmbracoSettings().Security.AllowPasswordReset},
{"loginBackgroundImage", UmbracoConfig.For.UmbracoSettings().Content.LoginBackgroundImage},
- {"emailServerConfigured", GlobalSettings.HasSmtpServerConfigured(_httpContext.Request.ApplicationPath)},
+ {"showUserInvite", EmailSender.CanSendRequiredEmail},
}
},
{
diff --git a/src/Umbraco.Web/Editors/PasswordChanger.cs b/src/Umbraco.Web/Editors/PasswordChanger.cs
index a6edd1bdd0..88e92c0ad2 100644
--- a/src/Umbraco.Web/Editors/PasswordChanger.cs
+++ b/src/Umbraco.Web/Editors/PasswordChanger.cs
@@ -98,8 +98,8 @@ namespace Umbraco.Web.Editors
_logger.Warn(string.Format("Could not reset user password {0}", errors));
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, errors: " + errors, new[] { "resetPassword" }) });
}
-
- return Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass });
+
+ return Attempt.Succeed(new PasswordChangedModel());
}
//we're not resetting it so we need to try to change it.
diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs
index 33b1d9dc08..18777395d3 100644
--- a/src/Umbraco.Web/Editors/UserGroupsController.cs
+++ b/src/Umbraco.Web/Editors/UserGroupsController.cs
@@ -133,7 +133,10 @@ namespace Umbraco.Web.Editors
[UserGroupAuthorization("userGroupIds")]
public HttpResponseMessage PostDeleteUserGroups([FromUri] int[] userGroupIds)
{
- var userGroups = Services.UserService.GetAllUserGroups(userGroupIds).ToArray();
+ var userGroups = Services.UserService.GetAllUserGroups(userGroupIds)
+ //never delete the admin group
+ .Where(x => x.Alias != Constants.Security.AdminGroupAlias)
+ .ToArray();
foreach (var userGroup in userGroups)
{
Services.UserService.DeleteUserGroup(userGroup);
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index cb2963124f..63484d1cec 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -265,13 +265,18 @@ namespace Umbraco.Web.Editors
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
-
- var existing = Services.UserService.GetByEmail(userSave.Email);
- if (existing != null)
+
+ if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail)
{
- ModelState.AddModelError("Email", "A user with the email already exists");
- throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
+ //ensure they are the same if we're using it
+ userSave.Username = userSave.Email;
}
+ else
+ {
+ //first validate the username if were showing it
+ CheckUniqueUsername(userSave.Username, null);
+ }
+ CheckUniqueEmail(userSave.Email, null);
//Perform authorization here to see if the current user can actually save this user with the info being requested
var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService);
@@ -283,7 +288,7 @@ namespace Umbraco.Web.Editors
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
//format is applied without us having to duplicate that logic
- var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Email, userSave.Email, GlobalSettings.DefaultUILanguage);
+ var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage);
identityUser.Name = userSave.Name;
var created = await UserManager.CreateAsync(identityUser);
@@ -345,21 +350,26 @@ namespace Umbraco.Web.Editors
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
-
- var hasSmtp = GlobalSettings.HasSmtpServerConfigured(RequestContext.VirtualPathRoot);
- if (hasSmtp == false)
+
+ if (EmailSender.CanSendRequiredEmail == false)
{
throw new HttpResponseException(
Request.CreateNotificationValidationErrorResponse("No Email server is configured"));
}
- var user = Services.UserService.GetByEmail(userSave.Email);
- if (user != null && (user.LastLoginDate != default(DateTime) || user.EmailConfirmedDate.HasValue))
+ IUser user;
+ if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail)
{
- ModelState.AddModelError("Email", "A user with the email already exists");
- throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
+ //ensure it's the same
+ userSave.Username = userSave.Email;
}
-
+ else
+ {
+ //first validate the username if we're showing it
+ user = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue);
+ }
+ user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue);
+
//Perform authorization here to see if the current user can actually save this user with the info being requested
var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService);
var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, user, null, null, userSave.UserGroups);
@@ -372,7 +382,7 @@ namespace Umbraco.Web.Editors
{
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
//format is applied without us having to duplicate that logic
- var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Email, userSave.Email, GlobalSettings.DefaultUILanguage);
+ var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage);
identityUser.Name = userSave.Name;
var created = await UserManager.CreateAsync(identityUser);
@@ -402,7 +412,31 @@ namespace Umbraco.Web.Editors
return display;
}
-
+
+ private IUser CheckUniqueEmail(string email, Func extraCheck)
+ {
+ var user = Services.UserService.GetByEmail(email);
+ if (user != null && (extraCheck == null || extraCheck(user)))
+ {
+ ModelState.AddModelError("Email", "A user with the email already exists");
+ throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
+ }
+ return user;
+ }
+
+ private IUser CheckUniqueUsername(string username, Func extraCheck)
+ {
+ var user = Services.UserService.GetByUsername(username);
+ if (user != null && (extraCheck == null || extraCheck(user)))
+ {
+ ModelState.AddModelError(
+ UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail ? "Email" : "Username",
+ "A user with the username already exists");
+ throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
+ }
+ return user;
+ }
+
private HttpContextBase EnsureHttpContext()
{
var attempt = this.TryGetHttpContext();
@@ -442,12 +476,15 @@ namespace Umbraco.Web.Editors
UserExtensions.GetUserCulture(to.Language, Services.TextService),
new[] { userDisplay.Name, from, message, inviteUri.ToString() });
- await UserManager.EmailService.SendAsync(new IdentityMessage
- {
- Body = emailBody,
- Destination = userDisplay.Email,
- Subject = emailSubject
- });
+ await UserManager.EmailService.SendAsync(
+ //send the special UmbracoEmailMessage which configures it's own sender
+ //to allow for events to handle sending the message if no smtp is configured
+ new UmbracoEmailMessage(new EmailSender(true))
+ {
+ Body = emailBody,
+ Destination = userDisplay.Email,
+ Subject = emailSubject
+ });
}
@@ -516,8 +553,7 @@ namespace Umbraco.Web.Editors
{
userSave.Username = userSave.Email;
}
-
- var resetPasswordValue = string.Empty;
+
if (userSave.ChangePassword != null)
{
var passwordChanger = new PasswordChanger(Logger, Services.UserService);
@@ -525,9 +561,6 @@ namespace Umbraco.Web.Editors
var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(Security.CurrentUser, found, userSave.ChangePassword, UserManager);
if (passwordChangeResult.Success)
{
- //depending on how the provider is configured, the password may be reset so let's store that for later
- resetPasswordValue = passwordChangeResult.Result.ResetPassword;
-
//need to re-get the user
found = Services.UserService.GetUserById(intId.Result);
}
@@ -551,11 +584,7 @@ namespace Umbraco.Web.Editors
Services.UserService.Save(user);
var display = Mapper.Map(user);
-
- //re-map the password reset value (if any)
- if (resetPasswordValue.IsNullOrWhiteSpace() == false)
- display.ResetPasswordValue = resetPasswordValue;
-
+
display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/operationSavedHeader"), Services.TextService.Localize("speechBubbles/editUserSaved"));
return display;
}
diff --git a/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
index c43fb0d3a1..998525c96a 100644
--- a/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
+++ b/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs
@@ -67,7 +67,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
var subject = _textService.Localize("healthcheck/scheduledHealthCheckEmailSubject");
- using (var client = new SmtpClient())
+ var mailSender = new EmailSender();
using (var mailMessage = new MailMessage(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress,
RecipientEmail,
string.IsNullOrEmpty(subject) ? "Umbraco Health Check Status" : subject,
@@ -77,14 +77,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
&& message.Contains("<") && message.Contains("")
})
{
- if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
- {
- await client.SendMailAsync(mailMessage);
- }
- else
- {
- client.Send(mailMessage);
- }
+ await mailSender.SendAsync(mailMessage);
}
}
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
index 06895ccc68..368067814d 100644
--- a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs
@@ -2,6 +2,8 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
namespace Umbraco.Web.Models.ContentEditing
{
@@ -18,7 +20,10 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "email", IsRequired = true)]
[Required]
[EmailAddress]
- public string Email { get; set; }
+ public string Email { get; set; }
+
+ [DataMember(Name = "username")]
+ public string Username { get; set; }
[DataMember(Name = "message")]
public string Message { get; set; }
@@ -26,7 +31,10 @@ namespace Umbraco.Web.Models.ContentEditing
public IEnumerable Validate(ValidationContext validationContext)
{
if (UserGroups.Any() == false)
- yield return new ValidationResult("A user must be assigned to at least one group", new[] { "UserGroups" });
+ yield return new ValidationResult("A user must be assigned to at least one group", new[] { "UserGroups" });
+
+ if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail == false && Username.IsNullOrWhiteSpace())
+ yield return new ValidationResult("A username cannot be empty", new[] { "Username" });
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
index 73b28ae669..46a756e0ad 100644
--- a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
+++ b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
@@ -35,6 +35,9 @@ namespace Umbraco.Web.Scheduling
{
if (_appContext == null) return true; // repeat...
+ if (Suspendable.ScheduledPublishing.CanRun == false)
+ return true; // repeat, later
+
switch (_appContext.GetCurrentServerRole())
{
case ServerRole.Slave:
diff --git a/src/Umbraco.Web/Search/ExamineEvents.cs b/src/Umbraco.Web/Search/ExamineEvents.cs
index 7fbbf29b89..e018bac214 100644
--- a/src/Umbraco.Web/Search/ExamineEvents.cs
+++ b/src/Umbraco.Web/Search/ExamineEvents.cs
@@ -24,7 +24,6 @@ namespace Umbraco.Web.Search
///
public sealed class ExamineEvents : ApplicationEventHandler
{
-
///
/// Once the application has started we should bind to all events and initialize the providers.
///
@@ -32,9 +31,9 @@ namespace Umbraco.Web.Search
///
///
/// We need to do this on the Started event as to guarantee that all resolvers are setup properly.
- ///
+ ///
protected override void ApplicationStarted(UmbracoApplicationBase httpApplication, ApplicationContext applicationContext)
- {
+ {
LogHelper.Info("Initializing Examine and binding to business logic events");
var registeredProviders = ExamineManager.Instance.IndexProviderCollection
@@ -46,14 +45,14 @@ namespace Umbraco.Web.Search
if (registeredProviders == 0)
return;
- //Bind to distributed cache events - this ensures that this logic occurs on ALL servers that are taking part
+ //Bind to distributed cache events - this ensures that this logic occurs on ALL servers that are taking part
// in a load balanced environment.
CacheRefresherBase.CacheUpdated += UnpublishedPageCacheRefresherCacheUpdated;
CacheRefresherBase.CacheUpdated += PublishedPageCacheRefresherCacheUpdated;
CacheRefresherBase.CacheUpdated += MediaCacheRefresherCacheUpdated;
CacheRefresherBase.CacheUpdated += MemberCacheRefresherCacheUpdated;
CacheRefresherBase.CacheUpdated += ContentTypeCacheRefresherCacheUpdated;
-
+
var contentIndexer = ExamineManager.Instance.IndexProviderCollection[Constants.Examine.InternalIndexer] as UmbracoContentIndexer;
if (contentIndexer != null)
{
@@ -77,6 +76,9 @@ namespace Umbraco.Web.Search
///
static void ContentTypeCacheRefresherCacheUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs e)
{
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
var indexersToUpdated = ExamineManager.Instance.IndexProviderCollection.OfType();
foreach (var provider in indexersToUpdated)
{
@@ -114,7 +116,7 @@ namespace Umbraco.Web.Search
}
}
- //TODO: We need to update Examine to support re-indexing multiple items at once instead of one by one which will speed up
+ //TODO: We need to update Examine to support re-indexing multiple items at once instead of one by one which will speed up
// the re-indexing process, we don't want to revert to rebuilding the whole thing!
if (contentTypesChanged.Count > 0)
@@ -129,8 +131,8 @@ namespace Umbraco.Web.Search
{
ReIndexForContent(contentItem, contentItem.HasPublishedVersion && contentItem.Trashed == false);
}
- }
- }
+ }
+ }
}
if (mediaTypesChanged.Count > 0)
{
@@ -163,11 +165,14 @@ namespace Umbraco.Web.Search
}
}
}
-
+
}
static void MemberCacheRefresherCacheUpdated(MemberCacheRefresher sender, CacheRefresherEventArgs e)
{
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
switch (e.MessageType)
{
case MessageType.RefreshById:
@@ -215,6 +220,9 @@ namespace Umbraco.Web.Search
///
static void MediaCacheRefresherCacheUpdated(MediaCacheRefresher sender, CacheRefresherEventArgs e)
{
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
switch (e.MessageType)
{
case MessageType.RefreshById:
@@ -252,13 +260,13 @@ namespace Umbraco.Web.Search
if (media1 != null)
{
ReIndexForMedia(media1, media1.Trashed == false);
- }
+ }
break;
case MediaCacheRefresher.OperationType.Trashed:
-
+
//keep if trashed for indexes supporting unpublished
//(delete the index from all indexes not supporting unpublished content)
-
+
DeleteIndexForEntity(payload.Id, true);
//We then need to re-index this item for all indexes supporting unpublished content
@@ -272,20 +280,20 @@ namespace Umbraco.Web.Search
case MediaCacheRefresher.OperationType.Deleted:
//permanently remove from all indexes
-
+
DeleteIndexForEntity(payload.Id, false);
break;
default:
throw new ArgumentOutOfRangeException();
- }
- }
+ }
+ }
}
break;
- case MessageType.RefreshByInstance:
- case MessageType.RemoveByInstance:
- case MessageType.RefreshAll:
+ case MessageType.RefreshByInstance:
+ case MessageType.RemoveByInstance:
+ case MessageType.RefreshAll:
default:
//We don't support these, these message types will not fire for media
break;
@@ -302,6 +310,9 @@ namespace Umbraco.Web.Search
///
static void PublishedPageCacheRefresherCacheUpdated(PageCacheRefresher sender, CacheRefresherEventArgs e)
{
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
switch (e.MessageType)
{
case MessageType.RefreshById:
@@ -312,8 +323,8 @@ namespace Umbraco.Web.Search
}
break;
case MessageType.RemoveById:
-
- //This is triggered when the item has been unpublished or trashed (which also performs an unpublish).
+
+ //This is triggered when the item has been unpublished or trashed (which also performs an unpublish).
var c2 = ApplicationContext.Current.Services.ContentService.GetById((int)e.MessageObject);
if (c2 != null)
@@ -368,6 +379,9 @@ namespace Umbraco.Web.Search
///
static void UnpublishedPageCacheRefresherCacheUpdated(UnpublishedPageCacheRefresher sender, CacheRefresherEventArgs e)
{
+ if (Suspendable.ExamineEvents.CanIndex == false)
+ return;
+
switch (e.MessageType)
{
case MessageType.RefreshById:
@@ -378,9 +392,9 @@ namespace Umbraco.Web.Search
}
break;
case MessageType.RemoveById:
-
+
// This is triggered when the item is permanently deleted
-
+
DeleteIndexForEntity((int)e.MessageObject, false);
break;
case MessageType.RefreshByInstance:
@@ -399,7 +413,7 @@ namespace Umbraco.Web.Search
{
DeleteIndexForEntity(c4.Id, false);
}
- break;
+ break;
case MessageType.RefreshByJson:
var jsonPayloads = UnpublishedPageCacheRefresher.DeserializeFromJsonPayload((string)e.MessageObject);
@@ -409,29 +423,28 @@ namespace Umbraco.Web.Search
{
switch (payload.Operation)
{
- case UnpublishedPageCacheRefresher.OperationType.Deleted:
+ case UnpublishedPageCacheRefresher.OperationType.Deleted:
//permanently remove from all indexes
-
+
DeleteIndexForEntity(payload.Id, false);
break;
default:
throw new ArgumentOutOfRangeException();
- }
- }
+ }
+ }
}
break;
- case MessageType.RefreshAll:
+ case MessageType.RefreshAll:
default:
//We don't support these, these message types will not fire for unpublished content
break;
}
}
-
private static void ReIndexForMember(IMember member)
{
ExamineManager.Instance.ReIndexNode(
@@ -447,7 +460,7 @@ namespace Umbraco.Web.Search
///
///
///
-
+
private static void IndexerDocumentWriting(object sender, DocumentWritingEventArgs e)
{
if (e.Fields.Keys.Contains("nodeName"))
@@ -463,7 +476,7 @@ namespace Umbraco.Web.Search
));
}
}
-
+
private static void ReIndexForMedia(IMedia sender, bool isMediaPublished)
{
var xml = sender.ToXml();
@@ -497,7 +510,7 @@ namespace Umbraco.Web.Search
//if keepIfUnpublished == true then only delete this item from indexes not supporting unpublished content,
// otherwise if keepIfUnpublished == false then remove from all indexes
-
+
.Where(x => keepIfUnpublished == false || x.SupportUnpublishedContent == false)
.Where(x => x.EnableDefaultEventHandler));
}
@@ -518,7 +531,7 @@ namespace Umbraco.Web.Search
ExamineManager.Instance.ReIndexNode(
xml, IndexTypes.Content,
ExamineManager.Instance.IndexProviderCollection.OfType()
-
+
//Index this item for all indexers if the content is published, otherwise if the item is not published
// then only index this for indexers supporting unpublished content
@@ -531,10 +544,10 @@ namespace Umbraco.Web.Search
///
///
/// true if data is going to be returned from cache
- ///
+ ///
[Obsolete("This method is no longer used and will be removed from the core in future versions, the cacheOnly parameter has no effect. Use the other ToXDocument overload instead")]
public static XDocument ToXDocument(Content node, bool cacheOnly)
- {
+ {
return ToXDocument(node);
}
@@ -542,7 +555,7 @@ namespace Umbraco.Web.Search
/// Converts a content node to Xml
///
///
- ///
+ ///
private static XDocument ToXDocument(Content node)
{
if (TypeHelper.IsTypeAssignableFrom(node))
@@ -561,7 +574,7 @@ namespace Umbraco.Web.Search
if (xNode.Attributes["nodeTypeAlias"] == null)
{
- //we'll add the nodeTypeAlias ourselves
+ //we'll add the nodeTypeAlias ourselves
XmlAttribute d = xDoc.CreateAttribute("nodeTypeAlias");
d.Value = node.ContentType.Alias;
xNode.Attributes.Append(d);
@@ -569,6 +582,5 @@ namespace Umbraco.Web.Search
return new XDocument(ExamineXmlExtensions.ToXElement(xNode));
}
-
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
index 69c926db3e..9953eea664 100644
--- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
+++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
@@ -90,7 +90,8 @@ namespace Umbraco.Web.Security.Identity
appContext.Services.UserService,
appContext.Services.EntityService,
appContext.Services.ExternalLoginService,
- userMembershipProvider));
+ userMembershipProvider,
+ UmbracoConfig.For.UmbracoSettings().Content));
app.SetBackOfficeUserManagerType();
@@ -119,7 +120,8 @@ namespace Umbraco.Web.Security.Identity
(options, owinContext) => BackOfficeUserManager.Create(
options,
customUserStore,
- userMembershipProvider));
+ userMembershipProvider,
+ UmbracoConfig.For.UmbracoSettings().Content));
app.SetBackOfficeUserManagerType();
diff --git a/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs
index 7034101a83..fdebf78480 100644
--- a/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs
+++ b/src/Umbraco.Web/Security/Providers/UsersMembershipProvider.cs
@@ -42,10 +42,36 @@ namespace Umbraco.Web.Security.Providers
return entity.AsConcreteMembershipUser(Name, true);
}
+ private bool _allowManuallyChangingPassword = false;
+ private bool _enablePasswordReset = false;
+
+ ///
+ /// Indicates whether the membership provider is configured to allow users to reset their passwords.
+ ///
+ ///
+ /// true if the membership provider supports password reset; otherwise, false. The default is FALSE for users.
+ public override bool EnablePasswordReset
+ {
+ get { return _enablePasswordReset; }
+ }
+
+ ///
+ /// For backwards compatibility, this provider supports this option by default it is FALSE for users
+ ///
+ public override bool AllowManuallyChangingPassword
+ {
+ get { return _allowManuallyChangingPassword; }
+ }
+
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
+ if (config == null) { throw new ArgumentNullException("config"); }
+
+ _allowManuallyChangingPassword = config.GetValue("allowManuallyChangingPassword", false);
+ _enablePasswordReset = config.GetValue("enablePasswordReset", false);
+
// test for membertype (if not specified, choose the first member type available)
// We'll support both names for legacy reasons: defaultUserTypeAlias & defaultUserGroupAlias
diff --git a/src/Umbraco.Web/Suspendable.cs b/src/Umbraco.Web/Suspendable.cs
new file mode 100644
index 0000000000..db4ef53485
--- /dev/null
+++ b/src/Umbraco.Web/Suspendable.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Diagnostics;
+using Examine;
+using Examine.Providers;
+using Umbraco.Core;
+using Umbraco.Web.Cache;
+
+namespace Umbraco.Web
+{
+ internal static class Suspendable
+ {
+ public static class PageCacheRefresher
+ {
+ private static bool _tried, _suspended;
+
+ public static bool CanRefreshDocumentCacheFromDatabase
+ {
+ get
+ {
+ // trying a full refresh
+ if (_suspended == false) return true;
+ _tried = true; // remember we tried
+ return false;
+ }
+ }
+
+ public static bool CanUpdateDocumentCache
+ {
+ get
+ {
+ // trying a partial update
+ // ok if not suspended, or if we haven't done a full already
+ return _suspended == false || _tried == false;
+ }
+ }
+
+ public static void SuspendDocumentCache()
+ {
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (PageCacheRefresher), "Suspend document cache.");
+ _suspended = true;
+ }
+
+ public static void ResumeDocumentCache()
+ {
+ _suspended = false;
+
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (PageCacheRefresher), string.Format("Resume document cache (reload:{0}).", _tried ? "true" : "false"));
+
+ if (_tried == false) return;
+ _tried = false;
+
+ var pageRefresher = CacheRefreshersResolver.Current.GetById(new Guid(DistributedCache.PageCacheRefresherId));
+ pageRefresher.RefreshAll();
+ }
+ }
+
+ public static class ExamineEvents
+ {
+ private static bool _tried, _suspended;
+
+ public static bool CanIndex
+ {
+ get
+ {
+ if (_suspended == false) return true;
+ _tried = true; // remember we tried
+ return false;
+ }
+ }
+
+ public static void SuspendIndexers()
+ {
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (ExamineEvents), "Suspend indexers.");
+ _suspended = true;
+ }
+
+ public static void ResumeIndexers()
+ {
+ _suspended = false;
+
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (ExamineEvents), string.Format("Resume indexers (rebuild:{0}).", _tried ? "true" : "false"));
+
+ if (_tried == false) return;
+ _tried = false;
+
+ // fixme - could we fork this on a background thread?
+ foreach (BaseIndexProvider indexer in ExamineManager.Instance.IndexProviderCollection)
+ {
+ indexer.RebuildIndex();
+ }
+ }
+ }
+
+ public static class ScheduledPublishing
+ {
+ private static bool _suspended;
+
+ public static bool CanRun
+ {
+ get { return _suspended == false; }
+ }
+
+ public static void Suspend()
+ {
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (ScheduledPublishing), "Suspend scheduled publishing.");
+ _suspended = true;
+ }
+
+ public static void Resume()
+ {
+ ApplicationContext.Current.ProfilingLogger.Logger.Info(typeof (ScheduledPublishing), "Resume scheduled publishing.");
+ _suspended = false;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index fb628ad137..e5b2568430 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -491,6 +491,7 @@
+
diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs
index 54bb1ac2f1..a7d40fa088 100644
--- a/src/Umbraco.Web/umbraco.presentation/content.cs
+++ b/src/Umbraco.Web/umbraco.presentation/content.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs
index 4ab89c5c7d..651cf9a9f4 100644
--- a/src/Umbraco.Web/umbraco.presentation/library.cs
+++ b/src/Umbraco.Web/umbraco.presentation/library.cs
@@ -1613,7 +1613,8 @@ namespace umbraco
public static void SendMail(string fromMail, string toMail, string subject, string body, bool isHtml)
{
try
- {
+ {
+ var mailSender = new EmailSender();
using (var mail = new MailMessage())
{
mail.From = new MailAddress(fromMail.Trim());
@@ -1622,8 +1623,7 @@ namespace umbraco
mail.Subject = subject;
mail.IsBodyHtml = isHtml;
mail.Body = body;
- using (var smtpClient = new SmtpClient())
- smtpClient.Send(mail);
+ mailSender.Send(mail);
}
}
catch (Exception ee)
diff --git a/src/umbraco.cms/businesslogic/translation/Translation.cs b/src/umbraco.cms/businesslogic/translation/Translation.cs
index 1cddf4e8e9..9c31cdb47d 100644
--- a/src/umbraco.cms/businesslogic/translation/Translation.cs
+++ b/src/umbraco.cms/businesslogic/translation/Translation.cs
@@ -59,6 +59,7 @@ namespace umbraco.cms.businesslogic.translation
{
try
{
+ var mailSender = new EmailSender();
using (var mail = new MailMessage())
{
mail.From = new MailAddress(user.Email.Trim());
@@ -66,8 +67,7 @@ namespace umbraco.cms.businesslogic.translation
mail.Subject = ui.Text("translation", "mailSubject", subjectVars, translator); ;
mail.IsBodyHtml = false;
mail.Body = ui.Text("translation", "mailBody", bodyVars, translator); ;
- using (var smtpClient = new SmtpClient())
- smtpClient.Send(mail);
+ mailSender.Send(mail);
}
}
catch (Exception ex)