Merge branch 'v9/dev' into v9/task/package-refactor
# Conflicts: # src/Umbraco.Web.BackOffice/Controllers/PackageController.cs # src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs
This commit is contained in:
2
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
- type: input
|
||||
id: "version"
|
||||
attributes:
|
||||
label: "Which Umbraco version are you using?"
|
||||
label: "Which *exact* Umbraco version are you using? For example: 8.13.1 - don't just write v8"
|
||||
description: "Use the help icon in the Umbraco backoffice to find the version you're using"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
23
src/Umbraco.Core/Configuration/ContentDashboardSettings.cs
Normal file
23
src/Umbraco.Core/Configuration/ContentDashboardSettings.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
namespace Umbraco.Core.Dashboards
|
||||
{
|
||||
public class ContentDashboardSettings
|
||||
{
|
||||
private const string DefaultContentDashboardPath = "cms";
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content dashboard should be available to all users.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the dashboard is visible for all user groups; otherwise, <c>false</c>
|
||||
/// and the default access rules for that dashboard will be in use.
|
||||
/// </value>
|
||||
public bool AllowContentDashboardAccessToAllUsers { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to use when constructing the URL for retrieving data for the content dashboard.
|
||||
/// </summary>
|
||||
/// <value>The URL path.</value>
|
||||
public string ContentDashboardPath { get; set; } = DefaultContentDashboardPath;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Cms.Core
|
||||
namespace Umbraco.Cms.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Cms.Core
|
||||
public const string WhereNodeId = "Umbraco.Web.PublishedCache.NuCache.DataSource.WhereNodeId";
|
||||
public const string WhereNodeIdX = "Umbraco.Web.PublishedCache.NuCache.DataSource.WhereNodeIdX";
|
||||
public const string SourcesSelectUmbracoNodeJoin = "Umbraco.Web.PublishedCache.NuCache.DataSource.SourcesSelectUmbracoNodeJoin";
|
||||
public const string ContentSourcesSelect = "Umbraco.Web.PublishedCache.NuCache.DataSource.ContentSourcesSelect";
|
||||
public const string ContentSourcesSelect = "Umbraco.Web.PublishedCache.NuCache.DataSource.ContentSourcesSelect";
|
||||
public const string ContentSourcesCount = "Umbraco.Web.PublishedCache.NuCache.DataSource.ContentSourcesCount";
|
||||
public const string MediaSourcesSelect = "Umbraco.Web.PublishedCache.NuCache.DataSource.MediaSourcesSelect";
|
||||
public const string MediaSourcesCount = "Umbraco.Web.PublishedCache.NuCache.DataSource.MediaSourcesCount";
|
||||
|
||||
@@ -188,12 +188,12 @@ namespace Umbraco.Cms.Core.Events
|
||||
siteUri,
|
||||
((IUser user, NotificationEmailSubjectParams subject) x)
|
||||
=> _textService.Localize(
|
||||
"notifications/mailSubject",
|
||||
"notifications", "mailSubject",
|
||||
x.user.GetUserCulture(_textService, _globalSettings),
|
||||
new[] { x.subject.SiteUrl, x.subject.Action, x.subject.ItemName }),
|
||||
((IUser user, NotificationEmailBodyParams body, bool isHtml) x)
|
||||
=> _textService.Localize(
|
||||
x.isHtml ? "notifications/mailBodyHtml" : "notifications/mailBody",
|
||||
"notifications", x.isHtml ? "mailBodyHtml" : "mailBody",
|
||||
x.user.GetUserCulture(_textService, _globalSettings),
|
||||
new[]
|
||||
{
|
||||
@@ -205,7 +205,7 @@ namespace Umbraco.Cms.Core.Events
|
||||
x.body.ItemId,
|
||||
//format the summary depending on if it's variant or not
|
||||
contentVariantGroup.Key == ContentVariation.Culture
|
||||
? (x.isHtml ? _textService.Localize("notifications/mailBodyVariantHtmlSummary", new[]{ x.body.Summary }) : _textService.Localize("notifications/mailBodyVariantSummary", new []{ x.body.Summary }))
|
||||
? (x.isHtml ? _textService.Localize("notifications", "mailBodyVariantHtmlSummary", new[]{ x.body.Summary }) : _textService.Localize("notifications","mailBodyVariantSummary", new []{ x.body.Summary }))
|
||||
: x.body.Summary,
|
||||
x.body.ItemUrl
|
||||
}));
|
||||
|
||||
@@ -31,10 +31,17 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
// we have a value
|
||||
// try to cast or convert it
|
||||
var value = property.GetValue(culture, segment);
|
||||
if (value is T valueAsT) return valueAsT;
|
||||
var value = property.GetValue(culture, segment);
|
||||
if (value is T valueAsT)
|
||||
{
|
||||
return valueAsT;
|
||||
}
|
||||
|
||||
var valueConverted = value.TryConvertTo<T>();
|
||||
if (valueConverted) return valueConverted.Result;
|
||||
if (valueConverted)
|
||||
{
|
||||
return valueConverted.Result;
|
||||
}
|
||||
|
||||
// cannot cast nor convert the value, nothing we can return but 'default'
|
||||
// note: we don't want to fallback in that case - would make little sense
|
||||
@@ -43,14 +50,23 @@ namespace Umbraco.Extensions
|
||||
|
||||
// we don't have a value, try fallback
|
||||
if (publishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var fallbackValue))
|
||||
{
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
// we don't have a value - neither direct nor fallback
|
||||
// give a chance to the converter to return something (eg empty enumerable)
|
||||
var noValue = property.GetValue(culture, segment);
|
||||
if (noValue is T noValueAsT) return noValueAsT;
|
||||
if (noValue is T noValueAsT)
|
||||
{
|
||||
return noValueAsT;
|
||||
}
|
||||
|
||||
var noValueConverted = noValue.TryConvertTo<T>();
|
||||
if (noValueConverted) return noValueConverted.Result;
|
||||
if (noValueConverted)
|
||||
{
|
||||
return noValueConverted.Result;
|
||||
}
|
||||
|
||||
// cannot cast noValue nor convert it, nothing we can return but 'default'
|
||||
return default;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks
|
||||
/// <summary>
|
||||
/// Gets the message for when the check has succeeded.
|
||||
/// </summary>
|
||||
public virtual string CheckSuccessMessage => LocalizedTextService.Localize("healthcheck/checkSuccessMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath });
|
||||
public virtual string CheckSuccessMessage => LocalizedTextService.Localize("healthcheck", "checkSuccessMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath });
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message for when the check has failed.
|
||||
@@ -62,10 +62,10 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks
|
||||
public virtual string CheckErrorMessage =>
|
||||
ValueComparisonType == ValueComparisonType.ShouldEqual
|
||||
? LocalizedTextService.Localize(
|
||||
"healthcheck/checkErrorMessageDifferentExpectedValue",
|
||||
"healthcheck", "checkErrorMessageDifferentExpectedValue",
|
||||
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath })
|
||||
: LocalizedTextService.Localize(
|
||||
"healthcheck/checkErrorMessageUnexpectedValue",
|
||||
"healthcheck", "checkErrorMessageUnexpectedValue",
|
||||
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath });
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Configuration
|
||||
/// </summary>
|
||||
public override string CheckSuccessMessage =>
|
||||
_textService.Localize(
|
||||
"healthcheck/macroErrorModeCheckSuccessMessage",
|
||||
"healthcheck","macroErrorModeCheckSuccessMessage",
|
||||
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value });
|
||||
|
||||
/// <summary>
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Configuration
|
||||
/// </summary>
|
||||
public override string CheckErrorMessage =>
|
||||
_textService.Localize(
|
||||
"healthcheck/macroErrorModeCheckErrorMessage",
|
||||
"healthcheck","macroErrorModeCheckErrorMessage",
|
||||
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -50,11 +50,11 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Configuration
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string CheckSuccessMessage =>
|
||||
LocalizedTextService.Localize("healthcheck/notificationEmailsCheckSuccessMessage",
|
||||
LocalizedTextService.Localize("healthcheck","notificationEmailsCheckSuccessMessage",
|
||||
new[] { CurrentValue ?? "<null>" });
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string CheckErrorMessage => LocalizedTextService.Localize("healthcheck/notificationEmailsCheckErrorMessage", new[] { DefaultFromEmail });
|
||||
public override string CheckErrorMessage => LocalizedTextService.Localize("healthcheck","notificationEmailsCheckErrorMessage", new[] { DefaultFromEmail });
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ReadMoreLink => Constants.HealthChecks.DocumentationLinks.Configuration.NotificationEmailCheck;
|
||||
|
||||
@@ -51,9 +51,9 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.LiveEnvironment
|
||||
public override string CurrentValue => _hostingSettings.CurrentValue.Debug.ToString();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string CheckSuccessMessage => LocalizedTextService.Localize("healthcheck/compilationDebugCheckSuccessMessage");
|
||||
public override string CheckSuccessMessage => LocalizedTextService.Localize("healthcheck","compilationDebugCheckSuccessMessage");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string CheckErrorMessage => LocalizedTextService.Localize("healthcheck/compilationDebugCheckErrorMessage");
|
||||
public override string CheckErrorMessage => LocalizedTextService.Localize("healthcheck","compilationDebugCheckErrorMessage");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,12 +95,12 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
}
|
||||
|
||||
message = success
|
||||
? LocalizedTextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderFound")
|
||||
: LocalizedTextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderNotFound");
|
||||
? LocalizedTextService.Localize($"healthcheck", $"{_localizedTextPrefix}CheckHeaderFound")
|
||||
: LocalizedTextService.Localize($"healthcheck", $"{_localizedTextPrefix}CheckHeaderNotFound");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
message = LocalizedTextService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
|
||||
message = LocalizedTextService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -68,12 +68,12 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
.ToArray();
|
||||
success = headersFound.Any() == false;
|
||||
message = success
|
||||
? _textService.Localize("healthcheck/excessiveHeadersNotFound")
|
||||
: _textService.Localize("healthcheck/excessiveHeadersFound", new[] { string.Join(", ", headersFound) });
|
||||
? _textService.Localize("healthcheck","excessiveHeadersNotFound")
|
||||
: _textService.Localize("healthcheck","excessiveHeadersFound", new[] { string.Join(", ", headersFound) });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
|
||||
message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -102,23 +102,23 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
if (s_certificateDaysToExpiry <= 0)
|
||||
{
|
||||
result = StatusResultType.Error;
|
||||
message = _textService.Localize("healthcheck/httpsCheckExpiredCertificate");
|
||||
message = _textService.Localize("healthcheck","httpsCheckExpiredCertificate");
|
||||
}
|
||||
else if (s_certificateDaysToExpiry < numberOfDaysForExpiryWarning)
|
||||
{
|
||||
result = StatusResultType.Warning;
|
||||
message = _textService.Localize("healthcheck/httpsCheckExpiringCertificate", new[] { s_certificateDaysToExpiry.ToString() });
|
||||
message = _textService.Localize("healthcheck","httpsCheckExpiringCertificate", new[] { s_certificateDaysToExpiry.ToString() });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StatusResultType.Success;
|
||||
message = _textService.Localize("healthcheck/httpsCheckValidCertificate");
|
||||
message = _textService.Localize("healthcheck","httpsCheckValidCertificate");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StatusResultType.Error;
|
||||
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, response.ReasonPhrase });
|
||||
message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, response.ReasonPhrase });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -127,12 +127,12 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
if (exception != null)
|
||||
{
|
||||
message = exception.Status == WebExceptionStatus.TrustFailure
|
||||
? _textService.Localize("healthcheck/httpsCheckInvalidCertificate", new[] { exception.Message })
|
||||
: _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, exception.Message });
|
||||
? _textService.Localize("healthcheck","httpsCheckInvalidCertificate", new[] { exception.Message })
|
||||
: _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, exception.Message });
|
||||
}
|
||||
else
|
||||
{
|
||||
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, ex.Message });
|
||||
message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, ex.Message });
|
||||
}
|
||||
|
||||
result = StatusResultType.Error;
|
||||
@@ -152,7 +152,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
Uri uri = _hostingEnvironment.ApplicationMainUrl;
|
||||
var success = uri.Scheme == "https";
|
||||
|
||||
return Task.FromResult(new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" }))
|
||||
return Task.FromResult(new HealthCheckStatus(_textService.Localize("healthcheck","httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" }))
|
||||
{
|
||||
ResultType = success ? StatusResultType.Success : StatusResultType.Error,
|
||||
ReadMoreLink = success ? null : Constants.HealthChecks.DocumentationLinks.Security.HttpsCheck.CheckIfCurrentSchemeIsHttps
|
||||
@@ -168,13 +168,13 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security
|
||||
StatusResultType resultType;
|
||||
if (uri.Scheme != "https")
|
||||
{
|
||||
resultMessage = _textService.Localize("healthcheck/httpsCheckConfigurationRectifyNotPossible");
|
||||
resultMessage = _textService.Localize("healthcheck","httpsCheckConfigurationRectifyNotPossible");
|
||||
resultType = StatusResultType.Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultMessage = _textService.Localize(
|
||||
"healthcheck/httpsCheckConfigurationCheckResult",
|
||||
"healthcheck","httpsCheckConfigurationCheckResult",
|
||||
new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" });
|
||||
resultType = httpsSettingEnabled ? StatusResultType.Success : StatusResultType.Error;
|
||||
}
|
||||
|
||||
@@ -56,21 +56,21 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Services
|
||||
string message;
|
||||
if (smtpSettings == null)
|
||||
{
|
||||
message = _textService.Localize("healthcheck/smtpMailSettingsNotFound");
|
||||
message = _textService.Localize("healthcheck", "smtpMailSettingsNotFound");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(smtpSettings.Host))
|
||||
{
|
||||
message = _textService.Localize("healthcheck/smtpMailSettingsHostNotConfigured");
|
||||
message = _textService.Localize("healthcheck", "smtpMailSettingsHostNotConfigured");
|
||||
}
|
||||
else
|
||||
{
|
||||
success = CanMakeSmtpConnection(smtpSettings.Host, smtpSettings.Port);
|
||||
message = success
|
||||
? _textService.Localize("healthcheck/smtpMailSettingsConnectionSuccess")
|
||||
? _textService.Localize("healthcheck", "smtpMailSettingsConnectionSuccess")
|
||||
: _textService.Localize(
|
||||
"healthcheck/smtpMailSettingsConnectionFail",
|
||||
"healthcheck", "smtpMailSettingsConnectionFail",
|
||||
new[] { smtpSettings.Host, smtpSettings.Port.ToString() });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Umbraco.Cms.Core.HealthChecks.NotificationMethods
|
||||
return;
|
||||
}
|
||||
|
||||
var message = _textService.Localize("healthcheck/scheduledHealthCheckEmailBody", new[]
|
||||
var message = _textService.Localize("healthcheck","scheduledHealthCheckEmailBody", new[]
|
||||
{
|
||||
DateTime.Now.ToShortDateString(),
|
||||
DateTime.Now.ToShortTimeString(),
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Cms.Core.HealthChecks.NotificationMethods
|
||||
// you can identify the site that these results are for.
|
||||
var host = _hostingEnvironment.ApplicationMainUrl?.ToString();
|
||||
|
||||
var subject = _textService.Localize("healthcheck/scheduledHealthCheckEmailSubject", new[] { host });
|
||||
var subject = _textService.Localize("healthcheck","scheduledHealthCheckEmailSubject", new[] { host });
|
||||
|
||||
|
||||
var mailMessage = CreateMailMessage(subject, message);
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
// localize content app names
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var localizedAppName = _localizedTextService.Localize($"apps/{app.Alias}");
|
||||
var localizedAppName = _localizedTextService.Localize("apps", app.Alias);
|
||||
if (localizedAppName.Equals($"[{app.Alias}]", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
app.Name = localizedAppName;
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
|
||||
if(!isCultureVariant && !isSegmentVariant)
|
||||
{
|
||||
return _localizedTextService.Localize("general/default");
|
||||
return _localizedTextService.Localize("general", "default");
|
||||
}
|
||||
|
||||
var parts = new List<string>();
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1")
|
||||
{
|
||||
isLockedOutProperty.View = "readonlyvalue";
|
||||
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
|
||||
isLockedOutProperty.Value = _localizedTextService.Localize("general", "no");
|
||||
}
|
||||
|
||||
if (_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
@@ -108,14 +108,14 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}id",
|
||||
Label = _localizedTextService.Localize("general/id"),
|
||||
Label = _localizedTextService.Localize("general","id"),
|
||||
Value = new List<string> {member.Id.ToString(), member.Key.ToString()},
|
||||
View = "idwithguid"
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype",
|
||||
Label = _localizedTextService.Localize("content/membertype"),
|
||||
Label = _localizedTextService.Localize("content","membertype"),
|
||||
Value = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, member.ContentType.Name),
|
||||
View = _propertyEditorCollection[Constants.PropertyEditors.Aliases.Label].GetValueEditor().View
|
||||
},
|
||||
@@ -123,7 +123,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}email",
|
||||
Label = _localizedTextService.Localize("general/email"),
|
||||
Label = _localizedTextService.Localize("general","email"),
|
||||
Value = member.Email,
|
||||
View = "email",
|
||||
Validation = {Mandatory = true}
|
||||
@@ -131,8 +131,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}password",
|
||||
Label = _localizedTextService.Localize("password"),
|
||||
|
||||
Label = _localizedTextService.Localize(null,"password"),
|
||||
Value = new Dictionary<string, object>
|
||||
{
|
||||
// TODO: why ignoreCase, what are we doing here?!
|
||||
@@ -146,7 +145,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}membergroup",
|
||||
Label = _localizedTextService.Localize("content/membergroup"),
|
||||
Label = _localizedTextService.Localize("content","membergroup"),
|
||||
Value = GetMemberGroupValue(member.Username),
|
||||
View = "membergroups",
|
||||
Config = new Dictionary<string, object> {{"IsRequired", true}}
|
||||
@@ -222,7 +221,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
var prop = new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}login",
|
||||
Label = localizedText.Localize("login"),
|
||||
Label = localizedText.Localize(null,"login"),
|
||||
Value = member.Username
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
private void Map(ISection source, Section target, MapperContext context)
|
||||
{
|
||||
target.Alias = source.Alias;
|
||||
target.Name = _textService.Localize("sections/" + source.Alias);
|
||||
target.Name = _textService.Localize("sections", source.Alias);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
tabs.Add(new Tab<ContentPropertyDisplay>
|
||||
{
|
||||
Id = 0,
|
||||
Label = LocalizedTextService.Localize("general/properties"),
|
||||
Label = LocalizedTextService.Localize("general", "properties"),
|
||||
Alias = "Generic properties",
|
||||
Properties = genericproperties
|
||||
});
|
||||
|
||||
@@ -284,8 +284,8 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
{
|
||||
target.AvailableCultures = _textService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName);
|
||||
target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator);
|
||||
target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Document, "content/contentRoot", context);
|
||||
target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Media, "media/mediaRoot", context);
|
||||
target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService,_appCaches), UmbracoObjectTypes.Document, "content","contentRoot", context);
|
||||
target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Media, "media","mediaRoot", context);
|
||||
target.CreateDate = source.CreateDate;
|
||||
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString();
|
||||
target.Email = source.Email;
|
||||
@@ -300,8 +300,8 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
target.Navigation = CreateUserEditorNavigation();
|
||||
target.ParentId = -1;
|
||||
target.Path = "-1," + source.Id;
|
||||
target.StartContentIds = GetStartNodes(source.StartContentIds.ToArray(), UmbracoObjectTypes.Document, "content/contentRoot", context);
|
||||
target.StartMediaIds = GetStartNodes(source.StartMediaIds.ToArray(), UmbracoObjectTypes.Media, "media/mediaRoot", context);
|
||||
target.StartContentIds = GetStartNodes(source.StartContentIds.ToArray(), UmbracoObjectTypes.Document, "content","contentRoot", context);
|
||||
target.StartMediaIds = GetStartNodes(source.StartMediaIds.ToArray(), UmbracoObjectTypes.Media, "media","mediaRoot", context);
|
||||
target.UpdateDate = source.UpdateDate;
|
||||
target.UserGroups = context.MapEnumerable<IReadOnlyUserGroup, UserGroupBasic>(source.Groups);
|
||||
target.Username = source.Username;
|
||||
@@ -358,12 +358,12 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
if (sourceStartMediaId > 0)
|
||||
target.MediaStartNode = context.Map<EntityBasic>(_entityService.Get(sourceStartMediaId.Value, UmbracoObjectTypes.Media));
|
||||
else if (sourceStartMediaId == -1)
|
||||
target.MediaStartNode = CreateRootNode(_textService.Localize("media/mediaRoot"));
|
||||
target.MediaStartNode = CreateRootNode(_textService.Localize("media", "mediaRoot"));
|
||||
|
||||
if (sourceStartContentId > 0)
|
||||
target.ContentStartNode = context.Map<EntityBasic>(_entityService.Get(sourceStartContentId.Value, UmbracoObjectTypes.Document));
|
||||
else if (sourceStartContentId == -1)
|
||||
target.ContentStartNode = CreateRootNode(_textService.Localize("content/contentRoot"));
|
||||
target.ContentStartNode = CreateRootNode(_textService.Localize("content", "contentRoot"));
|
||||
|
||||
if (target.Icon.IsNullOrWhiteSpace())
|
||||
target.Icon = Constants.Icons.UserGroup;
|
||||
@@ -375,10 +375,10 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
=> new Permission
|
||||
{
|
||||
Category = action.Category.IsNullOrWhiteSpace()
|
||||
? _textService.Localize($"actionCategories/{Constants.Conventions.PermissionCategories.OtherCategory}")
|
||||
: _textService.Localize($"actionCategories/{action.Category}"),
|
||||
Name = _textService.Localize($"actions/{action.Alias}"),
|
||||
Description = _textService.Localize($"actionDescriptions/{action.Alias}"),
|
||||
? _textService.Localize("actionCategories",Constants.Conventions.PermissionCategories.OtherCategory)
|
||||
: _textService.Localize("actionCategories", action.Category),
|
||||
Name = _textService.Localize("actions", action.Alias),
|
||||
Description = _textService.Localize("actionDescriptions", action.Alias),
|
||||
Icon = action.Icon,
|
||||
Checked = source.Permissions != null && source.Permissions.Contains(action.Letter.ToString(CultureInfo.InvariantCulture)),
|
||||
PermissionCode = action.Letter.ToString(CultureInfo.InvariantCulture)
|
||||
@@ -394,14 +394,14 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
private static string MapContentTypeIcon(IEntitySlim entity)
|
||||
=> entity is IContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
|
||||
|
||||
private IEnumerable<EntityBasic> GetStartNodes(int[] startNodeIds, UmbracoObjectTypes objectType, string localizedKey, MapperContext context)
|
||||
private IEnumerable<EntityBasic> GetStartNodes(int[] startNodeIds, UmbracoObjectTypes objectType, string localizedArea,string localizedAlias, MapperContext context)
|
||||
{
|
||||
if (startNodeIds.Length <= 0)
|
||||
return Enumerable.Empty<EntityBasic>();
|
||||
|
||||
var startNodes = new List<EntityBasic>();
|
||||
if (startNodeIds.Contains(-1))
|
||||
startNodes.Add(CreateRootNode(_textService.Localize(localizedKey)));
|
||||
startNodes.Add(CreateRootNode(_textService.Localize(localizedArea, localizedAlias)));
|
||||
|
||||
var mediaItems = _entityService.GetAll(objectType, startNodeIds);
|
||||
startNodes.AddRange(context.MapEnumerable<IEntitySlim, EntityBasic>(mediaItems));
|
||||
@@ -417,7 +417,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
Active = true,
|
||||
Alias = "details",
|
||||
Icon = "icon-umb-users",
|
||||
Name = _textService.Localize("general/user"),
|
||||
Name = _textService.Localize("general","user"),
|
||||
View = "views/users/views/user/details.html"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,12 +32,9 @@ namespace Umbraco.Cms.Core.Models.Trees
|
||||
public MenuItem(string alias, ILocalizedTextService textService)
|
||||
: this()
|
||||
{
|
||||
var values = textService.GetAllStoredValues(Thread.CurrentThread.CurrentUICulture);
|
||||
values.TryGetValue($"visuallyHiddenTexts/{alias}_description", out var textDescription);
|
||||
|
||||
Alias = alias;
|
||||
Name = textService.Localize($"actions/{Alias}");
|
||||
TextDescription = textDescription;
|
||||
Name = textService.Localize("actions", Alias);
|
||||
TextDescription = textService.Localize("visuallyHiddenTexts", alias + "_description", Thread.CurrentThread.CurrentUICulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
/// Determines if a property type's value should be compressed in memory
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
///
|
||||
/// </remarks>
|
||||
public interface IPropertyCacheCompression
|
||||
{
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
/// </summary>
|
||||
public class MediaPickerConfiguration : IIgnoreUserStartNodesConfig
|
||||
{
|
||||
[ConfigurationField("notice", "You can NOT change the property editor", "obsoletemediapickernotice")]
|
||||
public bool Notice { get; set; }
|
||||
|
||||
[ConfigurationField("multiPicker", "Pick multiple items", "boolean")]
|
||||
public bool Multiple { get; set; }
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Extensions
|
||||
|
||||
if (content.Published == false)
|
||||
{
|
||||
result.Add(UrlInfo.Message(textService.Localize("content/itemNotPublished")));
|
||||
result.Add(UrlInfo.Message(textService.Localize("content", "itemNotPublished")));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace Umbraco.Extensions
|
||||
|
||||
// deal with exceptions
|
||||
case "#ex":
|
||||
result.Add(UrlInfo.Message(textService.Localize("content/getUrlException"), culture));
|
||||
result.Add(UrlInfo.Message(textService.Localize("content", "getUrlException"), culture));
|
||||
break;
|
||||
|
||||
// got a URL, deal with collisions, add URL
|
||||
@@ -182,17 +182,17 @@ namespace Umbraco.Extensions
|
||||
if (parent == null)
|
||||
{
|
||||
// oops, internal error
|
||||
return UrlInfo.Message(textService.Localize("content/parentNotPublishedAnomaly"), culture);
|
||||
return UrlInfo.Message(textService.Localize("content", "parentNotPublishedAnomaly"), culture);
|
||||
}
|
||||
else if (!parent.Published)
|
||||
{
|
||||
// totally not published
|
||||
return UrlInfo.Message(textService.Localize("content/parentNotPublished", new[] { parent.Name }), culture);
|
||||
return UrlInfo.Message(textService.Localize("content", "parentNotPublished", new[] { parent.Name }), culture);
|
||||
}
|
||||
else
|
||||
{
|
||||
// culture not published
|
||||
return UrlInfo.Message(textService.Localize("content/parentCultureNotPublished", new[] {parent.Name}), culture);
|
||||
return UrlInfo.Message(textService.Localize("content", "parentCultureNotPublished", new[] {parent.Name}), culture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace Umbraco.Extensions
|
||||
logger.LogDebug(logMsg, url, uri, culture);
|
||||
}
|
||||
|
||||
var urlInfo = UrlInfo.Message(textService.Localize("content/routeErrorCannotRoute"), culture);
|
||||
var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture);
|
||||
return Attempt.Succeed(urlInfo);
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace Umbraco.Extensions
|
||||
l.Reverse();
|
||||
var s = "/" + string.Join("/", l) + " (id=" + pcr.PublishedContent.Id + ")";
|
||||
|
||||
var urlInfo = UrlInfo.Message(textService.Localize("content/routeError", new[] { s }), culture);
|
||||
var urlInfo = UrlInfo.Message(textService.Localize("content", "routeError", new[] { s }), culture);
|
||||
return Attempt.Succeed(urlInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -490,6 +490,11 @@ namespace Umbraco.Cms.Core.Services
|
||||
/// </summary>
|
||||
IContent Create(string name, int parentId, string documentTypeAlias, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a document
|
||||
/// </summary>
|
||||
IContent Create(string name, int parentId, IContentType contentType, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a document.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,10 @@ using System.Globalization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
// TODO: This needs to be merged into one interface in v9, but better yet
|
||||
// the Localize method should just the based on area + alias and we should remove
|
||||
// the one with the 'key' (the concatenated area/alias) to ensure that we never use that again.
|
||||
|
||||
/// <summary>
|
||||
/// The entry point to localize any key in the text storage source for a given culture
|
||||
/// </summary>
|
||||
@@ -15,11 +19,19 @@ namespace Umbraco.Cms.Core.Services
|
||||
/// <summary>
|
||||
/// Localize a key with variables
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <param name="tokens">This can be null</param>
|
||||
/// <returns></returns>
|
||||
string Localize(string key, CultureInfo culture, IDictionary<string, string> tokens = null);
|
||||
string Localize(string area, string alias, CultureInfo culture, IDictionary<string, string> tokens = null);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns all key/values in storage for the given culture
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDictionary<string, IDictionary<string, string>> GetAllStoredValuesByAreaAndAlias(CultureInfo culture);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all key/values in storage for the given culture
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -15,88 +16,81 @@ namespace Umbraco.Extensions
|
||||
/// </summary>
|
||||
public static class LocalizedTextServiceExtensions
|
||||
{
|
||||
public static string Localize<T>(this ILocalizedTextService manager, string area, T key)
|
||||
where T: System.Enum
|
||||
{
|
||||
var fullKey = string.Join("/", area, key);
|
||||
return manager.Localize(fullKey, Thread.CurrentThread.CurrentUICulture);
|
||||
}
|
||||
public static string Localize<T>(this ILocalizedTextService manager, string area, T key)
|
||||
where T: System.Enum =>
|
||||
manager.Localize(area, key.ToString(), Thread.CurrentThread.CurrentUICulture);
|
||||
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string key)
|
||||
{
|
||||
var fullKey = string.Join("/", area, key);
|
||||
return manager.Localize(fullKey, Thread.CurrentThread.CurrentUICulture);
|
||||
}
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture);
|
||||
|
||||
/// <summary>
|
||||
/// Localize using the current thread culture
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="tokens"></param>
|
||||
/// <returns></returns>
|
||||
public static string Localize(this ILocalizedTextService manager, string key, string[] tokens)
|
||||
{
|
||||
return manager.Localize(key, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
}
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, string[] tokens)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, ConvertToDictionaryVars(tokens));
|
||||
|
||||
/// <summary>
|
||||
/// Localize using the current thread culture
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="tokens"></param>
|
||||
/// <returns></returns>
|
||||
public static string Localize(this ILocalizedTextService manager, string key, IDictionary<string, string> tokens = null)
|
||||
{
|
||||
return manager.Localize(key, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
}
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, IDictionary<string, string> tokens = null)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
|
||||
/// <summary>
|
||||
/// Localize a key without any variables
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <param name="tokens"></param>
|
||||
/// <returns></returns>
|
||||
public static string Localize(this ILocalizedTextService manager, string key, CultureInfo culture, string[] tokens)
|
||||
{
|
||||
return manager.Localize(key, culture, ConvertToDictionaryVars(tokens));
|
||||
}
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, CultureInfo culture, string[] tokens)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
|
||||
/// <summary>
|
||||
/// Convert an array of strings to a dictionary of indices -> values
|
||||
/// </summary>
|
||||
/// <param name="variables"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDictionary<string, string> ConvertToDictionaryVars(string[] variables)
|
||||
{
|
||||
if (variables == null) return null;
|
||||
if (variables.Any() == false) return null;
|
||||
/// <summary>
|
||||
/// Convert an array of strings to a dictionary of indices -> values
|
||||
/// </summary>
|
||||
/// <param name="variables"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDictionary<string, string> ConvertToDictionaryVars(string[] variables)
|
||||
{
|
||||
if (variables == null) return null;
|
||||
if (variables.Any() == false) return null;
|
||||
|
||||
return variables.Select((s, i) => new { index = i.ToString(CultureInfo.InvariantCulture), value = s })
|
||||
.ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value);
|
||||
}
|
||||
return variables.Select((s, i) => new { index = i.ToString(CultureInfo.InvariantCulture), value = s })
|
||||
.ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value);
|
||||
}
|
||||
|
||||
public static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, ICultureDictionary cultureDictionary, string text)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
public static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, ICultureDictionary cultureDictionary, string text)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
|
||||
if (text.StartsWith("#") == false)
|
||||
return text;
|
||||
if (text.StartsWith("#") == false)
|
||||
return text;
|
||||
|
||||
text = text.Substring(1);
|
||||
var value = cultureDictionary[text];
|
||||
if (value.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
text = text.Substring(1);
|
||||
var value = cultureDictionary[text];
|
||||
if (value.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = manager.Localize(text.Replace('_', '/'));
|
||||
return value.StartsWith("[") ? text : value;
|
||||
}
|
||||
var areaAndKey = text.Split('_');
|
||||
|
||||
value = manager.Localize(areaAndKey[0], areaAndKey[1]);
|
||||
return value.StartsWith("[") ? text : value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Umbraco.Cms.Core.Trees
|
||||
var values = textService.GetAllStoredValues(Thread.CurrentThread.CurrentUICulture);
|
||||
values.TryGetValue($"visuallyHiddenTexts/{item.Alias}Description", out var textDescription);
|
||||
|
||||
var menuItem = new MenuItem(item, textService.Localize($"actions/{item.Alias}"))
|
||||
var menuItem = new MenuItem(item, textService.Localize($"actions", item.Alias))
|
||||
{
|
||||
SeparatorBefore = hasSeparator,
|
||||
OpensDialog = opensDialog,
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.Trees
|
||||
var label = $"[{tree.TreeAlias}]";
|
||||
|
||||
// try to look up a the localized tree header matching the tree alias
|
||||
var localizedLabel = textService.Localize("treeHeaders/" + tree.TreeAlias);
|
||||
var localizedLabel = textService.Localize("treeHeader", tree.TreeAlias);
|
||||
|
||||
// if the localizedLabel returns [alias] then return the title if it's defined
|
||||
if (localizedLabel != null && localizedLabel.Equals(label, StringComparison.InvariantCultureIgnoreCase))
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Examine;
|
||||
using Examine.Search;
|
||||
using Examine.Search;
|
||||
using Lucene.Net.QueryParsers.Classic;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
@@ -61,6 +62,15 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
var indexName = Constants.UmbracoIndexes.InternalIndexName;
|
||||
var fields = _treeSearcherFields.GetBackOfficeFields().ToList();
|
||||
|
||||
ISet<string> fieldsToLoad = new HashSet<string>(_treeSearcherFields.GetBackOfficeFieldsToLoad());
|
||||
|
||||
// TODO: WE should try to allow passing in a lucene raw query, however we will still need to do some manual string
|
||||
// manipulation for things like start paths, member types, etc...
|
||||
//if (Examine.ExamineExtensions.TryParseLuceneQuery(query))
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
//special GUID check since if a user searches on one specifically we need to escape it
|
||||
if (Guid.TryParse(query, out var g))
|
||||
{
|
||||
@@ -75,6 +85,11 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
indexName = Constants.UmbracoIndexes.MembersIndexName;
|
||||
type = "member";
|
||||
fields.AddRange(_treeSearcherFields.GetBackOfficeMembersFields());
|
||||
foreach(var field in _treeSearcherFields.GetBackOfficeMembersFieldsToLoad())
|
||||
{
|
||||
fieldsToLoad.Add(field);
|
||||
}
|
||||
|
||||
if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1")
|
||||
{
|
||||
sb.Append("+__NodeTypeAlias:");
|
||||
@@ -85,6 +100,11 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
case UmbracoEntityTypes.Media:
|
||||
type = "media";
|
||||
fields.AddRange(_treeSearcherFields.GetBackOfficeMediaFields());
|
||||
foreach (var field in _treeSearcherFields.GetBackOfficeMediaFieldsToLoad())
|
||||
{
|
||||
fieldsToLoad.Add(field);
|
||||
}
|
||||
|
||||
var allMediaStartNodes = currentUser != null
|
||||
? currentUser.CalculateMediaStartNodeIds(_entityService, _appCaches)
|
||||
: Array.Empty<int>();
|
||||
@@ -93,6 +113,10 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
case UmbracoEntityTypes.Document:
|
||||
type = "content";
|
||||
fields.AddRange(_treeSearcherFields.GetBackOfficeDocumentFields());
|
||||
foreach (var field in _treeSearcherFields.GetBackOfficeDocumentFieldsToLoad())
|
||||
{
|
||||
fieldsToLoad.Add(field);
|
||||
}
|
||||
var allContentStartNodes = currentUser != null
|
||||
? currentUser.CalculateContentStartNodeIds(_entityService, _appCaches)
|
||||
: Array.Empty<int>();
|
||||
@@ -113,7 +137,9 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
|
||||
var result = index.Searcher
|
||||
.CreateQuery()
|
||||
.NativeQuery(sb.ToString())
|
||||
.NativeQuery(sb.ToString())
|
||||
.SelectFields(fieldsToLoad)
|
||||
//only return the number of items specified to read up to the amount of records to fill from 0 -> the number of items on the page requested
|
||||
.Execute(QueryOptions.SkipTake(Convert.ToInt32(pageSize * pageIndex), pageSize));
|
||||
|
||||
totalFound = result.TotalItemCount;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex, IDisposable
|
||||
{
|
||||
private readonly ILogger<UmbracoContentIndex> _logger;
|
||||
|
||||
private readonly ISet<string> _idOnlyFieldSet = new HashSet<string> { "id" };
|
||||
public UmbracoContentIndex(
|
||||
ILoggerFactory loggerFactory,
|
||||
string name,
|
||||
@@ -133,7 +133,8 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
var rawQuery = $"{UmbracoExamineFieldNames.IndexPathFieldName}:{descendantPath}";
|
||||
var c = Searcher.CreateQuery();
|
||||
var filtered = c.NativeQuery(rawQuery);
|
||||
var results = filtered.Execute();
|
||||
var selectedFields = filtered.SelectFields(_idOnlyFieldSet);
|
||||
var results = selectedFields.Execute();
|
||||
|
||||
_logger.
|
||||
LogDebug("DeleteFromIndex with query: {Query} (found {TotalItems} results)", rawQuery, results.TotalItemCount);
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Umbraco.Cms.Core.Events
|
||||
item.Entity.WriterId,
|
||||
item.Entity.Id,
|
||||
ObjectTypes.GetName(UmbracoObjectTypes.Document),
|
||||
string.Format(_textService.Localize("recycleBin/contentTrashed"), item.Entity.Id, originalParentId)
|
||||
string.Format(_textService.Localize("recycleBin","contentTrashed"), item.Entity.Id, originalParentId)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ namespace Umbraco.Cms.Core.Events
|
||||
item.Entity.CreatorId,
|
||||
item.Entity.Id,
|
||||
ObjectTypes.GetName(UmbracoObjectTypes.Media),
|
||||
string.Format(_textService.Localize("recycleBin/mediaTrashed"), item.Entity.Id, originalParentId)
|
||||
string.Format(_textService.Localize("recycleBin","mediaTrashed"), item.Entity.Id, originalParentId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Examine;
|
||||
using Examine.Search;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Extensions;
|
||||
@@ -18,6 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
private readonly IIndex _index;
|
||||
private static readonly string[] s_ignoreProperties = { "Description" };
|
||||
|
||||
private readonly ISet<string> _idOnlyFieldSet = new HashSet<string> { "id" };
|
||||
public GenericIndexDiagnostics(IIndex index) => _index = index;
|
||||
|
||||
public int DocumentCount => -1; //unknown
|
||||
@@ -31,7 +33,7 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
|
||||
try
|
||||
{
|
||||
var result = _index.Searcher.Search("test");
|
||||
var result = _index.Searcher.CreateQuery().ManagedQuery("test").SelectFields(_idOnlyFieldSet).Execute(new QueryOptions(0, 1));
|
||||
return Attempt<string>.Succeed(); //if we can search we'll assume it's healthy
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -8,20 +8,28 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
public interface IUmbracoTreeSearcherFields
|
||||
{
|
||||
/// <summary>
|
||||
/// Propagate list of searchable fields for all node types
|
||||
/// The default index fields that are searched on in the back office search for umbraco content entities.
|
||||
/// </summary>
|
||||
IEnumerable<string> GetBackOfficeFields();
|
||||
|
||||
/// <summary>
|
||||
/// Propagate list of searchable fields for Members
|
||||
/// The additional index fields that are searched on in the back office for member entities.
|
||||
/// </summary>
|
||||
IEnumerable<string> GetBackOfficeMembersFields();
|
||||
|
||||
/// <summary>
|
||||
/// Propagate list of searchable fields for Media
|
||||
/// The additional index fields that are searched on in the back office for media entities.
|
||||
/// </summary>
|
||||
IEnumerable<string> GetBackOfficeMediaFields();
|
||||
|
||||
/// <summary>
|
||||
/// Propagate list of searchable fields for Documents
|
||||
/// The additional index fields that are searched on in the back office for document entities.
|
||||
/// </summary>
|
||||
IEnumerable<string> GetBackOfficeDocumentFields();
|
||||
|
||||
ISet<string> GetBackOfficeFieldsToLoad();
|
||||
ISet<string> GetBackOfficeMembersFieldsToLoad();
|
||||
ISet<string> GetBackOfficeDocumentFieldsToLoad();
|
||||
ISet<string> GetBackOfficeMediaFieldsToLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,8 @@ namespace Umbraco.Cms.Infrastructure.Examine
|
||||
public const string VariesByCultureFieldName = ExamineFieldNames.SpecialFieldPrefix + "VariesByCulture";
|
||||
|
||||
public const string NodeNameFieldName = "nodeName";
|
||||
public const string ItemIdFieldName ="__NodeId";
|
||||
public const string CategoryFieldName = "__IndexType";
|
||||
public const string ItemTypeFieldName = "__NodeTypeAlias";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class MediaPicker3ConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the configuration to ensure only valid crops are kept and have the correct width/height.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, MediaPicker3Configuration configuration)
|
||||
{
|
||||
var crops = new List<ImageCropperValue.ImageCropperCrop>();
|
||||
|
||||
var configuredCrops = configuration?.Crops;
|
||||
if (configuredCrops != null)
|
||||
{
|
||||
foreach (var configuredCrop in configuredCrops)
|
||||
{
|
||||
var crop = imageCropperValue.Crops?.FirstOrDefault(x => x.Alias == configuredCrop.Alias);
|
||||
|
||||
crops.Add(new ImageCropperValue.ImageCropperCrop
|
||||
{
|
||||
Alias = configuredCrop.Alias,
|
||||
Width = configuredCrop.Width,
|
||||
Height = configuredCrop.Height,
|
||||
Coordinates = crop?.Coordinates
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
imageCropperValue.Crops = crops;
|
||||
|
||||
if (configuration?.EnableLocalFocalPoint == false)
|
||||
{
|
||||
imageCropperValue.FocalPoint = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,29 @@ namespace Umbraco.Cms.Core
|
||||
IEnumerable<IPublishedContent> Media(IEnumerable<Guid> ids);
|
||||
IEnumerable<IPublishedContent> MediaAtRoot();
|
||||
|
||||
/// <summary>
|
||||
/// Searches content.
|
||||
/// </summary>
|
||||
/// <param name="term">The term to search.</param>
|
||||
/// <param name="skip">The amount of results to skip.</param>
|
||||
/// <param name="take">The amount of results to take/return.</param>
|
||||
/// <param name="totalRecords">The total amount of records.</param>
|
||||
/// <param name="culture">The culture (defaults to a culture insensitive search).</param>
|
||||
/// <param name="indexName">The name of the index to search (defaults to <see cref="Constants.UmbracoIndexes.ExternalIndexName" />).</param>
|
||||
/// <param name="loadedFields">The fields to load in the results of the search (defaults to all fields loaded).</param>
|
||||
/// <returns>
|
||||
/// The search results.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When the <paramref name="culture" /> is not specified or is *, all cultures are searched.
|
||||
/// To search for only invariant documents and fields use null.
|
||||
/// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents.
|
||||
/// </para>
|
||||
/// <para>While enumerating results, the ambient culture is changed to be the searched culture.</para>
|
||||
/// </remarks>
|
||||
IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet<string> loadedFields = null);
|
||||
|
||||
/// <summary>
|
||||
/// Searches content.
|
||||
/// </summary>
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
|
||||
target.Name = source.Values.ContainsKey(UmbracoExamineFieldNames.NodeNameFieldName) ? source.Values[UmbracoExamineFieldNames.NodeNameFieldName] : "[no name]";
|
||||
|
||||
var culture = context.GetCulture();
|
||||
var culture = context.GetCulture()?.ToLowerInvariant();
|
||||
if(culture.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
target.Name = source.Values.ContainsKey($"nodeName_{culture}") ? source.Values[$"nodeName_{culture}"] : target.Name;
|
||||
|
||||
@@ -1,17 +1,79 @@
|
||||
|
||||
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Model used in Razor Views for rendering
|
||||
/// Represents a media item with local crops.
|
||||
/// </summary>
|
||||
public class MediaWithCrops
|
||||
/// <seealso cref="PublishedContentWrapped" />
|
||||
public class MediaWithCrops : PublishedContentWrapped
|
||||
{
|
||||
public IPublishedContent MediaItem { get; set; }
|
||||
|
||||
public ImageCropperValue LocalCrops { get; set; }
|
||||
/// <summary>
|
||||
/// Gets the content/media item.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The content/media item.
|
||||
/// </value>
|
||||
public IPublishedContent Content => Unwrap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local crops.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The local crops.
|
||||
/// </value>
|
||||
public ImageCropperValue LocalCrops { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaWithCrops" /> class.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="publishedValueFallback">The published value fallback.</param>
|
||||
/// <param name="localCrops">The local crops.</param>
|
||||
public MediaWithCrops(IPublishedContent content, IPublishedValueFallback publishedValueFallback, ImageCropperValue localCrops)
|
||||
: base(content, publishedValueFallback)
|
||||
{
|
||||
LocalCrops = localCrops;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a media item with local crops.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the media item.</typeparam>
|
||||
/// <seealso cref="PublishedContentWrapped" />
|
||||
public class MediaWithCrops<T> : MediaWithCrops
|
||||
where T : IPublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the media item.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The media item.
|
||||
/// </value>
|
||||
public new T Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaWithCrops{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="publishedValueFallback">The published value fallback.</param>
|
||||
/// <param name="localCrops">The local crops.</param>
|
||||
public MediaWithCrops(T content,IPublishedValueFallback publishedValueFallback, ImageCropperValue localCrops)
|
||||
: base(content, publishedValueFallback, localCrops)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an implicit conversion from <see cref="MediaWithCrops{T}" /> to <see cref="T" />.
|
||||
/// </summary>
|
||||
/// <param name="mediaWithCrops">The media with crops.</param>
|
||||
/// <returns>
|
||||
/// The result of the conversion.
|
||||
/// </returns>
|
||||
public static implicit operator T(MediaWithCrops<T> mediaWithCrops) => mediaWithCrops.Content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Extends NPoco Database for Umbraco.
|
||||
/// </summary>
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|| (blockEditorData != null && validationLimit.Min.HasValue && blockEditorData.Layout.Count() < validationLimit.Min))
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
_textService.Localize("validation/entriesShort", new[]
|
||||
_textService.Localize("validation", "entriesShort", new[]
|
||||
{
|
||||
validationLimit.Min.ToString(),
|
||||
(validationLimit.Min - blockEditorData.Layout.Count()).ToString()
|
||||
@@ -276,7 +276,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
if (blockEditorData != null && validationLimit.Max.HasValue && blockEditorData.Layout.Count() > validationLimit.Max)
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
_textService.Localize("validation/entriesExceed", new[]
|
||||
_textService.Localize("validation", "entriesExceed", new[]
|
||||
{
|
||||
validationLimit.Max.ToString(),
|
||||
(blockEditorData.Layout.Count() - validationLimit.Max).ToString()
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
var items = Fields.First(x => x.Key == "items");
|
||||
|
||||
// customize the items field
|
||||
items.Name = textService.Localize("editdatatype/addPrevalue");
|
||||
items.Name = textService.Localize("editdatatype", "addPrevalue");
|
||||
items.Validators.Add(new ValueListUniqueValueValidator());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
@@ -26,4 +29,35 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
public int Height { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ImageCropperConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the configuration to ensure only valid crops are kept and have the correct width/height.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, ImageCropperConfiguration configuration)
|
||||
{
|
||||
var crops = new List<ImageCropperValue.ImageCropperCrop>();
|
||||
|
||||
var configuredCrops = configuration?.Crops;
|
||||
if (configuredCrops != null)
|
||||
{
|
||||
foreach (var configuredCrop in configuredCrops)
|
||||
{
|
||||
var crop = imageCropperValue.Crops?.FirstOrDefault(x => x.Alias == configuredCrop.Alias);
|
||||
|
||||
crops.Add(new ImageCropperValue.ImageCropperCrop
|
||||
{
|
||||
Alias = configuredCrop.Alias,
|
||||
Width = configuredCrop.Width,
|
||||
Height = configuredCrop.Height,
|
||||
Coordinates = crop?.Coordinates
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
imageCropperValue.Crops = crops;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
@@ -26,6 +31,9 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
private readonly IIOHelper _ioHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaPicker3PropertyEditor" /> class.
|
||||
/// </summary>
|
||||
public MediaPicker3PropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper,
|
||||
@@ -35,9 +43,11 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
_ioHelper = ioHelper;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() => new MediaPicker3ConfigurationEditor(_ioHelper);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create<MediaPicker3PropertyValueEditor>(Attribute);
|
||||
|
||||
internal class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference
|
||||
@@ -55,6 +65,13 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public override object ToEditor(IProperty property, string culture = null, string segment = null)
|
||||
{
|
||||
var value = property.GetValue(culture, segment);
|
||||
|
||||
return Deserialize(_jsonSerializer, value);
|
||||
}
|
||||
|
||||
///<remarks>
|
||||
/// Note: no FromEditor() and ToEditor() methods
|
||||
/// We do not want to transform the way the data is stored in the DB and would like to keep a raw JSON string
|
||||
@@ -62,19 +79,70 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|
||||
public IEnumerable<UmbracoEntityReference> GetReferences(object value)
|
||||
{
|
||||
var rawJson = value == null ? string.Empty : value is string str ? str : value.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rawJson))
|
||||
yield break;
|
||||
|
||||
var mediaWithCropsDtos = _jsonSerializer.Deserialize<MediaPickerWithCropsValueConverter.MediaWithCropsDto[]>(rawJson);
|
||||
|
||||
foreach (var mediaWithCropsDto in mediaWithCropsDtos)
|
||||
foreach (var dto in Deserialize(_jsonSerializer, value))
|
||||
{
|
||||
yield return new UmbracoEntityReference(GuidUdi.Create(Constants.UdiEntityType.Media, mediaWithCropsDto.MediaKey));
|
||||
yield return new UmbracoEntityReference(Udi.Create(Constants.UdiEntityType.Media, dto.MediaKey));
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<MediaWithCropsDto> Deserialize(IJsonSerializer jsonSerializer,object value)
|
||||
{
|
||||
var rawJson = value is string str ? str : value?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(rawJson))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!rawJson.DetectIsJson())
|
||||
{
|
||||
// Old comma seperated UDI format
|
||||
foreach (var udiStr in rawJson.Split(Constants.CharArrays.Comma))
|
||||
{
|
||||
if (UdiParser.TryParse(udiStr, out GuidUdi udi))
|
||||
{
|
||||
yield return new MediaWithCropsDto
|
||||
{
|
||||
Key = Guid.NewGuid(),
|
||||
MediaKey = udi.Guid,
|
||||
Crops = Enumerable.Empty<ImageCropperValue.ImageCropperCrop>(),
|
||||
FocalPoint = new ImageCropperValue.ImageCropperFocalPoint
|
||||
{
|
||||
Left = 0.5m,
|
||||
Top = 0.5m
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// New JSON format
|
||||
foreach (var dto in jsonSerializer.Deserialize<IEnumerable<MediaWithCropsDto>>(rawJson))
|
||||
{
|
||||
yield return dto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Model/DTO that represents the JSON that the MediaPicker3 stores.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
internal class MediaWithCropsDto
|
||||
{
|
||||
[DataMember(Name = "key")]
|
||||
public Guid Key { get; set; }
|
||||
|
||||
[DataMember(Name = "mediaKey")]
|
||||
public Guid MediaKey { get; set; }
|
||||
|
||||
[DataMember(Name = "crops")]
|
||||
public IEnumerable<ImageCropperValue.ImageCropperCrop> Crops { get; set; }
|
||||
|
||||
[DataMember(Name = "focalPoint")]
|
||||
public ImageCropperValue.ImageCropperFocalPoint FocalPoint { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
public override object ToEditor(IProperty property, string culture = null, string segment = null)
|
||||
{
|
||||
var val = property.GetValue(culture, segment);
|
||||
var valEditors = new Dictionary<int, IDataValueEditor>();
|
||||
|
||||
var rows = _nestedContentValues.GetPropertyValues(val);
|
||||
|
||||
@@ -186,8 +187,15 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
continue;
|
||||
}
|
||||
|
||||
var tempConfig = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId).Configuration;
|
||||
var valEditor = propEditor.GetValueEditor(tempConfig);
|
||||
var dataTypeId = prop.Value.PropertyType.DataTypeId;
|
||||
if (!valEditors.TryGetValue(dataTypeId, out var valEditor))
|
||||
{
|
||||
var tempConfig = _dataTypeService.GetDataType(dataTypeId).Configuration;
|
||||
valEditor = propEditor.GetValueEditor(tempConfig);
|
||||
|
||||
valEditors.Add(dataTypeId, valEditor);
|
||||
}
|
||||
|
||||
var convValue = valEditor.ToEditor(tempProp);
|
||||
|
||||
// update the raw value since this is what will get serialized out
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
//we only store a single value for this editor so the 'member' or 'field'
|
||||
// we'll associate this error with will simply be called 'value'
|
||||
yield return new ValidationResult(_localizedTextService.Localize("errors/dissallowedMediaType"), new[] { "value" });
|
||||
yield return new ValidationResult(_localizedTextService.Localize("errors", "dissallowedMediaType"), new[] { "value" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
settingsData = null;
|
||||
}
|
||||
|
||||
// TODO: This should be optimized/cached, as calling Activator.CreateInstance is slow
|
||||
var layoutType = typeof(BlockListItem<,>).MakeGenericType(contentData.GetType(), settingsData?.GetType() ?? typeof(IPublishedElement));
|
||||
var layoutRef = (BlockListItem)Activator.CreateInstance(layoutType, contentGuidUdi, contentData, settingGuidUdi, settingsData);
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
/// Determines whether the value has a specified crop.
|
||||
/// </summary>
|
||||
public bool HasCrop(string alias)
|
||||
=> Crops.Any(x => x.Alias == alias);
|
||||
=> Crops != null && Crops.Any(x => x.Alias == alias);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the value has a source image.
|
||||
@@ -138,46 +138,35 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
public bool HasImage()
|
||||
=> !string.IsNullOrWhiteSpace(Src);
|
||||
|
||||
/// <summary>
|
||||
/// Applies a configuration.
|
||||
/// </summary>
|
||||
/// <remarks>Ensures that all crops defined in the configuration exists in the value.</remarks>
|
||||
public void ApplyConfiguration(ImageCropperConfiguration configuration)
|
||||
public ImageCropperValue Merge(ImageCropperValue imageCropperValue)
|
||||
{
|
||||
// merge the crop values - the alias + width + height comes from
|
||||
// configuration, but each crop can store its own coordinates
|
||||
|
||||
var configuredCrops = configuration?.Crops;
|
||||
if (configuredCrops == null) return;
|
||||
|
||||
//Use Crops if it's not null, otherwise create a new list
|
||||
var crops = Crops?.ToList() ?? new List<ImageCropperCrop>();
|
||||
|
||||
foreach (var configuredCrop in configuredCrops)
|
||||
var incomingCrops = imageCropperValue?.Crops;
|
||||
if (incomingCrops != null)
|
||||
{
|
||||
var crop = crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias);
|
||||
if (crop != null)
|
||||
foreach (var incomingCrop in incomingCrops)
|
||||
{
|
||||
// found, apply the height & width
|
||||
crop.Width = configuredCrop.Width;
|
||||
crop.Height = configuredCrop.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not found, add
|
||||
crops.Add(new ImageCropperCrop
|
||||
var crop = crops.FirstOrDefault(x => x.Alias == incomingCrop.Alias);
|
||||
if (crop == null)
|
||||
{
|
||||
Alias = configuredCrop.Alias,
|
||||
Width = configuredCrop.Width,
|
||||
Height = configuredCrop.Height
|
||||
});
|
||||
// Add incoming crop
|
||||
crops.Add(incomingCrop);
|
||||
}
|
||||
else if (crop.Coordinates == null)
|
||||
{
|
||||
// Use incoming crop coordinates
|
||||
crop.Coordinates = incomingCrop.Coordinates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assume we don't have to remove the crops in value, that
|
||||
// are not part of configuration anymore?
|
||||
|
||||
Crops = crops;
|
||||
return new ImageCropperValue()
|
||||
{
|
||||
Src = !string.IsNullOrWhiteSpace(Src) ? Src : imageCropperValue?.Src,
|
||||
Crops = crops,
|
||||
FocalPoint = FocalPoint ?? imageCropperValue?.FocalPoint
|
||||
};
|
||||
}
|
||||
|
||||
#region IEquatable
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
@@ -15,110 +13,85 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class MediaPickerWithCropsValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
|
||||
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
||||
private readonly IPublishedUrlProvider _publishedUrlProvider;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
public MediaPickerWithCropsValueConverter(
|
||||
IPublishedSnapshotAccessor publishedSnapshotAccessor,
|
||||
IPublishedUrlProvider publishedUrlProvider)
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
|
||||
_publishedUrlProvider = publishedUrlProvider;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias.Equals(Core.Constants.PropertyEditors.Aliases.MediaPicker3);
|
||||
|
||||
public override bool? IsValue(object value, PropertyValueLevel level)
|
||||
{
|
||||
var isValue = base.IsValue(value, level);
|
||||
if (isValue != false && level == PropertyValueLevel.Source)
|
||||
{
|
||||
// Empty JSON array is not a value
|
||||
isValue = value?.ToString() != "[]";
|
||||
}
|
||||
|
||||
return isValue;
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> IsMultipleDataType(propertyType.DataType)
|
||||
? typeof(IEnumerable<MediaWithCrops>)
|
||||
: typeof(MediaWithCrops);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot;
|
||||
|
||||
/// <summary>
|
||||
/// Enusre this property value convertor is for the New Media Picker with Crops aka MediaPicker 3
|
||||
/// </summary>
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias.Equals(Core.Constants.PropertyEditors.Aliases.MediaPicker3);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the raw JSON value is not an empty array
|
||||
/// </summary>
|
||||
public override bool? IsValue(object value, PropertyValueLevel level) => value?.ToString() != "[]";
|
||||
|
||||
/// <summary>
|
||||
/// What C# model type does the raw JSON return for Models & Views
|
||||
/// </summary>
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
{
|
||||
// Check do we want to return IPublishedContent collection still or a NEW model ?
|
||||
var isMultiple = IsMultipleDataType(propertyType.DataType);
|
||||
return isMultiple
|
||||
? typeof(IEnumerable<MediaWithCrops>)
|
||||
: typeof(MediaWithCrops);
|
||||
}
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) => source?.ToString();
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
var mediaItems = new List<MediaWithCrops>();
|
||||
var isMultiple = IsMultipleDataType(propertyType.DataType);
|
||||
if (inter == null)
|
||||
if (string.IsNullOrEmpty(inter?.ToString()))
|
||||
{
|
||||
return isMultiple ? mediaItems: null;
|
||||
// Short-circuit on empty value
|
||||
return isMultiple ? Enumerable.Empty<MediaWithCrops>() : null;
|
||||
}
|
||||
|
||||
var dtos = JsonConvert.DeserializeObject<IEnumerable<MediaWithCropsDto>>(inter.ToString());
|
||||
var mediaItems = new List<MediaWithCrops>();
|
||||
var dtos = MediaPicker3PropertyEditor.MediaPicker3PropertyValueEditor.Deserialize(_jsonSerializer, inter);
|
||||
var configuration = propertyType.DataType.ConfigurationAs<MediaPicker3Configuration>();
|
||||
|
||||
foreach(var media in dtos)
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var item = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(media.MediaKey);
|
||||
if (item != null)
|
||||
var mediaItem = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(preview, dto.MediaKey);
|
||||
if (mediaItem != null)
|
||||
{
|
||||
mediaItems.Add(new MediaWithCrops
|
||||
var localCrops = new ImageCropperValue
|
||||
{
|
||||
MediaItem = item,
|
||||
LocalCrops = new ImageCropperValue
|
||||
{
|
||||
Crops = media.Crops,
|
||||
FocalPoint = media.FocalPoint,
|
||||
Src = item.Url(_publishedUrlProvider)
|
||||
}
|
||||
});
|
||||
Crops = dto.Crops,
|
||||
FocalPoint = dto.FocalPoint,
|
||||
Src = mediaItem.Url(_publishedUrlProvider)
|
||||
};
|
||||
|
||||
localCrops.ApplyConfiguration(configuration);
|
||||
|
||||
// TODO: This should be optimized/cached, as calling Activator.CreateInstance is slow
|
||||
var mediaWithCropsType = typeof(MediaWithCrops<>).MakeGenericType(mediaItem.GetType());
|
||||
var mediaWithCrops = (MediaWithCrops)Activator.CreateInstance(mediaWithCropsType, mediaItem, localCrops);
|
||||
|
||||
mediaItems.Add(mediaWithCrops);
|
||||
|
||||
if (!isMultiple)
|
||||
{
|
||||
// Short-circuit on single item
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isMultiple ? mediaItems : FirstOrDefault(mediaItems);
|
||||
return isMultiple ? mediaItems : mediaItems.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the media picker configured to pick multiple media items
|
||||
/// </summary>
|
||||
/// <param name="dataType"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsMultipleDataType(PublishedDataType dataType)
|
||||
{
|
||||
var config = dataType.ConfigurationAs<MediaPicker3Configuration>();
|
||||
return config.Multiple;
|
||||
}
|
||||
|
||||
private object FirstOrDefault(IList mediaItems)
|
||||
{
|
||||
return mediaItems.Count == 0 ? null : mediaItems[0];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Model/DTO that represents the JSON that the MediaPicker3 stores
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
internal class MediaWithCropsDto
|
||||
{
|
||||
[DataMember(Name = "key")]
|
||||
public Guid Key { get; set; }
|
||||
|
||||
[DataMember(Name = "mediaKey")]
|
||||
public Guid MediaKey { get; set; }
|
||||
|
||||
[DataMember(Name = "crops")]
|
||||
public IEnumerable<ImageCropperValue.ImageCropperCrop> Crops { get; set; }
|
||||
|
||||
[DataMember(Name = "focalPoint")]
|
||||
public ImageCropperValue.ImageCropperFocalPoint FocalPoint { get; set; }
|
||||
}
|
||||
private bool IsMultipleDataType(PublishedDataType dataType) => dataType.ConfigurationAs<MediaPicker3Configuration>().Multiple;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
var items = Fields.First(x => x.Key == "items");
|
||||
|
||||
// customize the items field
|
||||
items.Name = textService.Localize("editdatatype/addPrevalue");
|
||||
items.Name = textService.Localize("editdatatype", "addPrevalue");
|
||||
items.Validators.Add(new ValueListUniqueValueValidator());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.XPath;
|
||||
using Examine;
|
||||
using Examine.Search;
|
||||
@@ -237,6 +236,10 @@ namespace Umbraco.Cms.Infrastructure
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords,
|
||||
string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName)
|
||||
=> Search(term, skip, take, out totalRecords, culture, indexName, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet<string> loadedFields = null)
|
||||
{
|
||||
if (skip < 0)
|
||||
{
|
||||
@@ -284,6 +287,10 @@ namespace Umbraco.Cms.Infrastructure
|
||||
.ToArray(); // Get all index fields suffixed with the culture name supplied
|
||||
queryExecutor = query.ManagedQuery(term, fields);
|
||||
}
|
||||
if (loadedFields != null && queryExecutor is IBooleanOperation booleanOperation)
|
||||
{
|
||||
queryExecutor = booleanOperation.SelectFields(loadedFields);
|
||||
}
|
||||
|
||||
var results = skip == 0 && take == 0
|
||||
? queryExecutor.Execute()
|
||||
|
||||
@@ -1,31 +1,61 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Examine;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Search
|
||||
{
|
||||
public class UmbracoTreeSearcherFields : IUmbracoTreeSearcherFields
|
||||
{
|
||||
private IReadOnlyList<string> _backOfficeFields = new List<string> {"id", "__NodeId", "__Key"};
|
||||
public IEnumerable<string> GetBackOfficeFields()
|
||||
{
|
||||
return _backOfficeFields;
|
||||
}
|
||||
|
||||
|
||||
private IReadOnlyList<string> _backOfficeMembersFields = new List<string> {"email", "loginName"};
|
||||
public IEnumerable<string> GetBackOfficeMembersFields()
|
||||
{
|
||||
return _backOfficeMembersFields;
|
||||
}
|
||||
private IReadOnlyList<string> _backOfficeFields = new List<string> {"id", UmbracoExamineFieldNames.ItemIdFieldName, UmbracoExamineFieldNames.NodeKeyFieldName};
|
||||
private readonly ISet<string> _backOfficeFieldsToLoad = new HashSet<string> { "id", UmbracoExamineFieldNames.ItemIdFieldName, UmbracoExamineFieldNames.NodeKeyFieldName, "nodeName", UmbracoExamineFieldNames.IconFieldName, UmbracoExamineFieldNames.CategoryFieldName, "parentID", UmbracoExamineFieldNames.ItemTypeFieldName };
|
||||
private IReadOnlyList<string> _backOfficeMediaFields = new List<string> { UmbracoExamineFieldNames.UmbracoFileFieldName };
|
||||
public IEnumerable<string> GetBackOfficeMediaFields()
|
||||
private readonly ISet<string> _backOfficeMediaFieldsToLoad = new HashSet<string> { UmbracoExamineFieldNames.UmbracoFileFieldName };
|
||||
private IReadOnlyList<string> _backOfficeMembersFields = new List<string> { "email", "loginName" };
|
||||
private readonly ISet<string> _backOfficeMembersFieldsToLoad = new HashSet<string> { "email", "loginName" };
|
||||
private readonly ISet<string> _backOfficeDocumentFieldsToLoad = new HashSet<string> { UmbracoExamineFieldNames.VariesByCultureFieldName };
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public UmbracoTreeSearcherFields(ILocalizationService localizationService)
|
||||
{
|
||||
return _backOfficeMediaFields;
|
||||
_localizationService = localizationService;
|
||||
}
|
||||
public IEnumerable<string> GetBackOfficeDocumentFields()
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> GetBackOfficeFields() => _backOfficeFields;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> GetBackOfficeMembersFields() => _backOfficeMembersFields;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> GetBackOfficeMediaFields() => _backOfficeMediaFields;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> GetBackOfficeDocumentFields() => Enumerable.Empty<string>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISet<string> GetBackOfficeFieldsToLoad() => _backOfficeFieldsToLoad;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISet<string> GetBackOfficeMembersFieldsToLoad() => _backOfficeMembersFieldsToLoad;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISet<string> GetBackOfficeMediaFieldsToLoad() => _backOfficeMediaFieldsToLoad;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISet<string> GetBackOfficeDocumentFieldsToLoad()
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
var fields = _backOfficeDocumentFieldsToLoad;
|
||||
|
||||
// We need to load all nodeName_* fields but we won't know those up front so need to get
|
||||
// all langs (this is cached)
|
||||
foreach(var field in _localizationService.GetAllLanguages().Select(x => "nodeName_" + x.IsoCode.ToLowerInvariant()))
|
||||
{
|
||||
fields.Add(field);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,43 +17,43 @@ namespace Umbraco.Cms.Core.Security
|
||||
public override IdentityError DuplicateRoleName(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateRoleName),
|
||||
Description = _textService.Localize("validation/duplicateUserGroupName", new[] { role })
|
||||
Description = _textService.Localize("validation", "duplicateUserGroupName", new[] { role })
|
||||
};
|
||||
|
||||
public override IdentityError InvalidRoleName(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidRoleName),
|
||||
Description = _textService.Localize("validation/invalidUserGroupName")
|
||||
Description = _textService.Localize("validation", "invalidUserGroupName")
|
||||
};
|
||||
|
||||
public override IdentityError LoginAlreadyAssociated() => new IdentityError
|
||||
{
|
||||
Code = nameof(LoginAlreadyAssociated),
|
||||
Description = _textService.Localize("user/duplicateLogin")
|
||||
Description = _textService.Localize("user", "duplicateLogin")
|
||||
};
|
||||
|
||||
public override IdentityError UserAlreadyHasPassword() => new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyHasPassword),
|
||||
Description = _textService.Localize("user/userHasPassword")
|
||||
Description = _textService.Localize("user", "userHasPassword")
|
||||
};
|
||||
|
||||
public override IdentityError UserAlreadyInRole(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyInRole),
|
||||
Description = _textService.Localize("user/userHasGroup", new[] { role })
|
||||
Description = _textService.Localize("user", "userHasGroup", new[] { role })
|
||||
};
|
||||
|
||||
public override IdentityError UserLockoutNotEnabled() => new IdentityError
|
||||
{
|
||||
Code = nameof(UserLockoutNotEnabled),
|
||||
Description = _textService.Localize("user/userLockoutNotEnabled")
|
||||
Description = _textService.Localize("user", "userLockoutNotEnabled")
|
||||
};
|
||||
|
||||
public override IdentityError UserNotInRole(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(UserNotInRole),
|
||||
Description = _textService.Localize("user/userNotInGroup", new[] { role })
|
||||
Description = _textService.Localize("user", "userNotInGroup", new[] { role })
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,43 +67,43 @@ namespace Umbraco.Cms.Core.Security
|
||||
public override IdentityError DuplicateRoleName(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateRoleName),
|
||||
Description = _textService.Localize("validation/duplicateMemberGroupName", new[] { role })
|
||||
Description = _textService.Localize("validation", "duplicateMemberGroupName", new[] { role })
|
||||
};
|
||||
|
||||
public override IdentityError InvalidRoleName(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidRoleName),
|
||||
Description = _textService.Localize("validation/invalidMemberGroupName")
|
||||
Description = _textService.Localize("validation", "invalidMemberGroupName")
|
||||
};
|
||||
|
||||
public override IdentityError LoginAlreadyAssociated() => new IdentityError
|
||||
{
|
||||
Code = nameof(LoginAlreadyAssociated),
|
||||
Description = _textService.Localize("member/duplicateMemberLogin")
|
||||
Description = _textService.Localize("member", "duplicateMemberLogin")
|
||||
};
|
||||
|
||||
public override IdentityError UserAlreadyHasPassword() => new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyHasPassword),
|
||||
Description = _textService.Localize("member/memberHasPassword")
|
||||
Description = _textService.Localize("member", "memberHasPassword")
|
||||
};
|
||||
|
||||
public override IdentityError UserAlreadyInRole(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyInRole),
|
||||
Description = _textService.Localize("member/memberHasGroup", new[] { role })
|
||||
Description = _textService.Localize("member", "memberHasGroup", new[] { role })
|
||||
};
|
||||
|
||||
public override IdentityError UserLockoutNotEnabled() => new IdentityError
|
||||
{
|
||||
Code = nameof(UserLockoutNotEnabled),
|
||||
Description = _textService.Localize("member/memberLockoutNotEnabled")
|
||||
Description = _textService.Localize("member", "memberLockoutNotEnabled")
|
||||
};
|
||||
|
||||
public override IdentityError UserNotInRole(string role) => new IdentityError
|
||||
{
|
||||
Code = nameof(UserNotInRole),
|
||||
Description = _textService.Localize("member/memberNotInGroup", new[] { role })
|
||||
Description = _textService.Localize("member", "memberNotInGroup", new[] { role })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,91 +13,91 @@ namespace Umbraco.Cms.Core.Security
|
||||
public override IdentityError ConcurrencyFailure() => new IdentityError
|
||||
{
|
||||
Code = nameof(ConcurrencyFailure),
|
||||
Description = _textService.Localize("errors/concurrencyError")
|
||||
Description = _textService.Localize("errors", "concurrencyError")
|
||||
};
|
||||
|
||||
public override IdentityError DefaultError() => new IdentityError
|
||||
{
|
||||
Code = nameof(DefaultError),
|
||||
Description = _textService.Localize("errors/defaultError")
|
||||
Description = _textService.Localize("errors", "defaultError")
|
||||
};
|
||||
|
||||
public override IdentityError DuplicateEmail(string email) => new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateEmail),
|
||||
Description = _textService.Localize("validation/duplicateEmail", new[] { email })
|
||||
Description = _textService.Localize("validation", "duplicateEmail", new[] { email })
|
||||
};
|
||||
|
||||
public override IdentityError DuplicateUserName(string userName) => new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateUserName),
|
||||
Description = _textService.Localize("validation/duplicateUsername", new[] { userName })
|
||||
Description = _textService.Localize("validation", "duplicateUsername", new[] { userName })
|
||||
};
|
||||
|
||||
public override IdentityError InvalidEmail(string email) => new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidEmail),
|
||||
Description = _textService.Localize("validation/invalidEmail")
|
||||
Description = _textService.Localize("validation", "invalidEmail")
|
||||
};
|
||||
|
||||
public override IdentityError InvalidToken() => new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidToken),
|
||||
Description = _textService.Localize("validation/invalidToken")
|
||||
Description = _textService.Localize("validation", "invalidToken")
|
||||
};
|
||||
|
||||
public override IdentityError InvalidUserName(string userName) => new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidUserName),
|
||||
Description = _textService.Localize("validation/invalidUsername")
|
||||
Description = _textService.Localize("validation", "invalidUsername")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordMismatch() => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordMismatch),
|
||||
Description = _textService.Localize("user/passwordMismatch")
|
||||
Description = _textService.Localize("user", "passwordMismatch")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordRequiresDigit() => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresDigit),
|
||||
Description = _textService.Localize("user/passwordRequiresDigit")
|
||||
Description = _textService.Localize("user", "passwordRequiresDigit")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordRequiresLower() => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresLower),
|
||||
Description = _textService.Localize("user/passwordRequiresLower")
|
||||
Description = _textService.Localize("user", "passwordRequiresLower")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordRequiresNonAlphanumeric() => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresNonAlphanumeric),
|
||||
Description = _textService.Localize("user/passwordRequiresNonAlphanumeric")
|
||||
Description = _textService.Localize("user", "passwordRequiresNonAlphanumeric")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars) => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresUniqueChars),
|
||||
Description = _textService.Localize("user/passwordRequiresUniqueChars", new[] { uniqueChars.ToString() })
|
||||
Description = _textService.Localize("user", "passwordRequiresUniqueChars", new[] { uniqueChars.ToString() })
|
||||
};
|
||||
|
||||
public override IdentityError PasswordRequiresUpper() => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresUpper),
|
||||
Description = _textService.Localize("user/passwordRequiresUpper")
|
||||
Description = _textService.Localize("user", "passwordRequiresUpper")
|
||||
};
|
||||
|
||||
public override IdentityError PasswordTooShort(int length) => new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordTooShort),
|
||||
Description = _textService.Localize("user/passwordTooShort", new[] { length.ToString() })
|
||||
Description = _textService.Localize("user", "passwordTooShort", new[] { length.ToString() })
|
||||
};
|
||||
|
||||
public override IdentityError RecoveryCodeRedemptionFailed() => new IdentityError
|
||||
{
|
||||
Code = nameof(RecoveryCodeRedemptionFailed),
|
||||
Description = _textService.Localize("login/resetCodeExpired")
|
||||
Description = _textService.Localize("login", "resetCodeExpired")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,11 +194,34 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// TODO: what about culture?
|
||||
|
||||
var contentType = GetContentType(contentTypeAlias);
|
||||
if (contentType == null)
|
||||
throw new ArgumentException("No content type with that alias.", nameof(contentTypeAlias));
|
||||
return Create(name, parentId, contentType, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object of a specified content type.
|
||||
/// </summary>
|
||||
/// <remarks>This method simply returns a new, non-persisted, IContent without any identity. It
|
||||
/// is intended as a shortcut to creating new content objects that does not invoke a save
|
||||
/// operation against the database.
|
||||
/// </remarks>
|
||||
/// <param name="name">The name of the content object.</param>
|
||||
/// <param name="parentId">The identifier of the parent, or -1.</param>
|
||||
/// <param name="contentType">The content type of the content</param>
|
||||
/// <param name="userId">The optional id of the user creating the content.</param>
|
||||
/// <returns>The content object.</returns>
|
||||
public IContent Create(string name, int parentId, IContentType contentType,
|
||||
int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
if (contentType is null)
|
||||
{
|
||||
throw new ArgumentException("Content type must be specified", nameof(contentType));
|
||||
}
|
||||
|
||||
var parent = parentId > 0 ? GetById(parentId) : null;
|
||||
if (parentId > 0 && parent == null)
|
||||
if (parentId > 0 && parent is null)
|
||||
{
|
||||
throw new ArgumentException("No content with that id.", nameof(parentId));
|
||||
}
|
||||
|
||||
var content = new Content(name, parentId, contentType, userId);
|
||||
|
||||
|
||||
@@ -5,19 +5,18 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
// TODO: Convert all of this over to Niels K's localization framework one day
|
||||
|
||||
public class LocalizedTextService : ILocalizedTextService
|
||||
{
|
||||
private readonly ILogger<LocalizedTextService> _logger;
|
||||
private readonly Lazy<LocalizedTextServiceFileSources> _fileSources;
|
||||
private readonly IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource;
|
||||
private readonly IDictionary<CultureInfo, Lazy<XDocument>> _xmlSource;
|
||||
|
||||
private IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource => _dictionarySourceLazy.Value;
|
||||
private IDictionary<CultureInfo, IDictionary<string, string>> _noAreaDictionarySource => _noAreaDictionarySourceLazy.Value;
|
||||
private readonly Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>> _dictionarySourceLazy;
|
||||
private readonly Lazy<IDictionary<CultureInfo, IDictionary<string, string>>> _noAreaDictionarySourceLazy;
|
||||
private readonly char[] _splitter = new[] { '/' };
|
||||
/// <summary>
|
||||
/// Initializes with a file sources instance
|
||||
/// </summary>
|
||||
@@ -25,12 +24,50 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="logger"></param>
|
||||
public LocalizedTextService(Lazy<LocalizedTextServiceFileSources> fileSources, ILogger<LocalizedTextService> logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger;
|
||||
if (fileSources == null) throw new ArgumentNullException("fileSources");
|
||||
if (fileSources == null) throw new ArgumentNullException(nameof(fileSources));
|
||||
_dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(() => FileSourcesToAreaDictionarySources(fileSources.Value));
|
||||
_noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => FileSourcesToNoAreaDictionarySources(fileSources.Value));
|
||||
_fileSources = fileSources;
|
||||
}
|
||||
|
||||
private IDictionary<CultureInfo, IDictionary<string, string>> FileSourcesToNoAreaDictionarySources(LocalizedTextServiceFileSources fileSources)
|
||||
{
|
||||
var xmlSources = fileSources.GetXmlSources();
|
||||
|
||||
return XmlSourceToNoAreaDictionary(xmlSources);
|
||||
}
|
||||
|
||||
private IDictionary<CultureInfo, IDictionary<string, string>> XmlSourceToNoAreaDictionary(IDictionary<CultureInfo, Lazy<XDocument>> xmlSources)
|
||||
{
|
||||
var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
|
||||
foreach (var xmlSource in xmlSources)
|
||||
{
|
||||
var noAreaAliasValue = GetNoAreaStoredTranslations(xmlSources, xmlSource.Key);
|
||||
cultureNoAreaDictionary.Add(xmlSource.Key, noAreaAliasValue);
|
||||
}
|
||||
return cultureNoAreaDictionary;
|
||||
}
|
||||
|
||||
private IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> FileSourcesToAreaDictionarySources(LocalizedTextServiceFileSources fileSources)
|
||||
{
|
||||
var xmlSources = fileSources.GetXmlSources();
|
||||
return XmlSourcesToAreaDictionary(xmlSources);
|
||||
}
|
||||
|
||||
private IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> XmlSourcesToAreaDictionary(IDictionary<CultureInfo, Lazy<XDocument>> xmlSources)
|
||||
{
|
||||
var cultureDictionary = new Dictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>();
|
||||
foreach (var xmlSource in xmlSources)
|
||||
{
|
||||
var areaAliaValue = GetAreaStoredTranslations(xmlSources, xmlSource.Key);
|
||||
cultureDictionary.Add(xmlSource.Key, areaAliaValue);
|
||||
|
||||
}
|
||||
return cultureDictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes with an XML source
|
||||
/// </summary>
|
||||
@@ -38,12 +75,15 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="logger"></param>
|
||||
public LocalizedTextService(IDictionary<CultureInfo, Lazy<XDocument>> source, ILogger<LocalizedTextService> logger)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_xmlSource = source;
|
||||
_logger = logger;
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(() => XmlSourcesToAreaDictionary(source));
|
||||
_noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => XmlSourceToNoAreaDictionary(source));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes with a source of a dictionary of culture -> areas -> sub dictionary of keys/values
|
||||
/// </summary>
|
||||
@@ -51,37 +91,54 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="logger"></param>
|
||||
public LocalizedTextService(IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> source, ILogger<LocalizedTextService> logger)
|
||||
{
|
||||
_dictionarySource = source ?? throw new ArgumentNullException(nameof(source));
|
||||
var dictionarySource = source ?? throw new ArgumentNullException(nameof(source));
|
||||
_dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(() => dictionarySource);
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
|
||||
foreach (var cultureDictionary in dictionarySource)
|
||||
{
|
||||
var areaAliaValue = GetAreaStoredTranslations(source, cultureDictionary.Key);
|
||||
var aliasValue = new Dictionary<string, string>();
|
||||
foreach (var area in areaAliaValue)
|
||||
{
|
||||
foreach (var alias in area.Value)
|
||||
{
|
||||
if (!aliasValue.ContainsKey(alias.Key))
|
||||
{
|
||||
aliasValue.Add(alias.Key, alias.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
cultureNoAreaDictionary.Add(cultureDictionary.Key, aliasValue);
|
||||
}
|
||||
_noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => cultureNoAreaDictionary);
|
||||
}
|
||||
|
||||
public string Localize(string key, CultureInfo culture, IDictionary<string, string> tokens = null)
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
|
||||
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
//This is what the legacy ui service did
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return string.Empty;
|
||||
|
||||
var keyParts = key.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
var keyParts = key.Split(_splitter, StringSplitOptions.RemoveEmptyEntries);
|
||||
var area = keyParts.Length > 1 ? keyParts[0] : null;
|
||||
var alias = keyParts.Length > 1 ? keyParts[1] : keyParts[0];
|
||||
return Localize(area, alias, culture, tokens);
|
||||
}
|
||||
public string Localize(string area, string alias, CultureInfo culture, IDictionary<string, string> tokens = null)
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.Value.GetXmlSources()
|
||||
: null);
|
||||
//This is what the legacy ui service did
|
||||
if (string.IsNullOrEmpty(alias))
|
||||
return string.Empty;
|
||||
|
||||
if (xmlSource != null)
|
||||
{
|
||||
return GetFromXmlSource(xmlSource, culture, area, alias, tokens);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetFromDictionarySource(culture, area, alias, tokens);
|
||||
}
|
||||
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
return GetFromDictionarySource(culture, area, alias, tokens);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,76 +146,105 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// </summary>
|
||||
public IDictionary<string, string> GetAllStoredValues(CultureInfo culture)
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException("culture");
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
|
||||
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.Value.GetXmlSources()
|
||||
: null);
|
||||
|
||||
if (xmlSource != null)
|
||||
if (_dictionarySource.ContainsKey(culture) == false)
|
||||
{
|
||||
if (xmlSource.ContainsKey(culture) == false)
|
||||
_logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture);
|
||||
return new Dictionary<string, string>(0);
|
||||
}
|
||||
IDictionary<string, string> result = new Dictionary<string, string>();
|
||||
//convert all areas + keys to a single key with a '/'
|
||||
foreach (var area in _dictionarySource[culture])
|
||||
{
|
||||
foreach (var key in area.Value)
|
||||
{
|
||||
_logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture);
|
||||
return result;
|
||||
}
|
||||
|
||||
// convert all areas + keys to a single key with a '/'
|
||||
result = GetStoredTranslations(xmlSource, culture);
|
||||
|
||||
// merge with the English file in case there's keys in there that don't exist in the local file
|
||||
var englishCulture = CultureInfo.GetCultureInfo("en-US");
|
||||
if (culture.Equals(englishCulture) == false)
|
||||
{
|
||||
var englishResults = GetStoredTranslations(xmlSource, englishCulture);
|
||||
foreach (var englishResult in englishResults.Where(englishResult => result.ContainsKey(englishResult.Key) == false))
|
||||
var dictionaryKey = string.Format("{0}/{1}", area.Key, key.Key);
|
||||
//i don't think it's possible to have duplicates because we're dealing with a dictionary in the first place, but we'll double check here just in case.
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
{
|
||||
result.Add(englishResult.Key, englishResult.Value);
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_dictionarySource.ContainsKey(culture) == false)
|
||||
{
|
||||
_logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture);
|
||||
return result;
|
||||
}
|
||||
|
||||
// convert all areas + keys to a single key with a '/'
|
||||
foreach (var area in _dictionarySource[culture])
|
||||
{
|
||||
foreach (var key in area.Value)
|
||||
{
|
||||
var dictionaryKey = string.Format("{0}/{1}", area.Key, key.Key);
|
||||
// i don't think it's possible to have duplicates because we're dealing with a dictionary in the first place, but we'll double check here just in case.
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
{
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetStoredTranslations(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo cult)
|
||||
private Dictionary<string, IDictionary<string, string>> GetAreaStoredTranslations(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo cult)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
var overallResult = new Dictionary<string, IDictionary<string, string>>(StringComparer.InvariantCulture);
|
||||
var areas = xmlSource[cult].Value.XPathSelectElements("//area");
|
||||
foreach (var area in areas)
|
||||
{
|
||||
var result = new Dictionary<string, string>(StringComparer.InvariantCulture);
|
||||
var keys = area.XPathSelectElements("./key");
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var dictionaryKey = string.Format("{0}/{1}", (string)area.Attribute("alias"),
|
||||
(string)key.Attribute("alias"));
|
||||
var dictionaryKey =
|
||||
(string)key.Attribute("alias");
|
||||
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
}
|
||||
overallResult.Add(area.Attribute("alias").Value, result);
|
||||
}
|
||||
|
||||
//Merge English Dictionary
|
||||
var englishCulture = new CultureInfo("en-US");
|
||||
if (!cult.Equals(englishCulture))
|
||||
{
|
||||
var enUS = xmlSource[englishCulture].Value.XPathSelectElements("//area");
|
||||
foreach (var area in enUS)
|
||||
{
|
||||
IDictionary<string, string> result = new Dictionary<string, string>(StringComparer.InvariantCulture);
|
||||
if (overallResult.ContainsKey(area.Attribute("alias").Value))
|
||||
{
|
||||
result = overallResult[area.Attribute("alias").Value];
|
||||
}
|
||||
var keys = area.XPathSelectElements("./key");
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var dictionaryKey =
|
||||
(string)key.Attribute("alias");
|
||||
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
}
|
||||
if (!overallResult.ContainsKey(area.Attribute("alias").Value))
|
||||
{
|
||||
overallResult.Add(area.Attribute("alias").Value, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return overallResult;
|
||||
}
|
||||
private Dictionary<string, string> GetNoAreaStoredTranslations(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo cult)
|
||||
{
|
||||
var result = new Dictionary<string, string>(StringComparer.InvariantCulture);
|
||||
var keys = xmlSource[cult].Value.XPathSelectElements("//key");
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var dictionaryKey =
|
||||
(string)key.Attribute("alias");
|
||||
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
}
|
||||
|
||||
//Merge English Dictionary
|
||||
var englishCulture = new CultureInfo("en-US");
|
||||
if (!cult.Equals(englishCulture))
|
||||
{
|
||||
var keysEn = xmlSource[englishCulture].Value.XPathSelectElements("//key");
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var dictionaryKey =
|
||||
(string)key.Attribute("alias");
|
||||
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
|
||||
if (result.ContainsKey(dictionaryKey) == false)
|
||||
result.Add(dictionaryKey, key.Value);
|
||||
@@ -166,6 +252,25 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private Dictionary<string, IDictionary<string, string>> GetAreaStoredTranslations(IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> dictionarySource, CultureInfo cult)
|
||||
{
|
||||
var overallResult = new Dictionary<string, IDictionary<string, string>>(StringComparer.InvariantCulture);
|
||||
var areaDict = dictionarySource[cult];
|
||||
|
||||
foreach (var area in areaDict)
|
||||
{
|
||||
var result = new Dictionary<string, string>(StringComparer.InvariantCulture);
|
||||
var keys = area.Value.Keys;
|
||||
foreach (var key in keys)
|
||||
{
|
||||
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
|
||||
if (result.ContainsKey(key) == false)
|
||||
result.Add(key, area.Value[key]);
|
||||
}
|
||||
overallResult.Add(area.Key, result);
|
||||
}
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all currently supported cultures
|
||||
@@ -173,11 +278,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <returns></returns>
|
||||
public IEnumerable<CultureInfo> GetSupportedCultures()
|
||||
{
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.Value.GetXmlSources()
|
||||
: null);
|
||||
|
||||
return xmlSource != null ? xmlSource.Keys : _dictionarySource.Keys;
|
||||
return _dictionarySource.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,27 +314,25 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
var cultureSource = _dictionarySource[culture];
|
||||
|
||||
string found;
|
||||
if (area.IsNullOrWhiteSpace())
|
||||
string found = null;
|
||||
if (string.IsNullOrWhiteSpace(area))
|
||||
{
|
||||
found = cultureSource
|
||||
.SelectMany(x => x.Value)
|
||||
.Where(keyvals => keyvals.Key.InvariantEquals(key))
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefault();
|
||||
_noAreaDictionarySource[culture].TryGetValue(key, out found);
|
||||
}
|
||||
else
|
||||
{
|
||||
found = cultureSource
|
||||
.Where(areas => areas.Key.InvariantEquals(area))
|
||||
.SelectMany(a => a.Value)
|
||||
.Where(keyvals => keyvals.Key.InvariantEquals(key))
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefault();
|
||||
if (_dictionarySource[culture].TryGetValue(area, out var areaDictionary))
|
||||
{
|
||||
areaDictionary.TryGetValue(key, out found);
|
||||
}
|
||||
if (found == null)
|
||||
{
|
||||
_noAreaDictionarySource[culture].TryGetValue(key, out found);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
return ParseTokens(found, tokens);
|
||||
@@ -242,44 +341,6 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
//NOTE: Based on how legacy works, the default text does not contain the area, just the key
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
private string GetFromXmlSource(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
|
||||
{
|
||||
if (xmlSource.ContainsKey(culture) == false)
|
||||
{
|
||||
_logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture);
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
var found = FindTranslation(xmlSource, culture, area, key);
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
return ParseTokens(found.Value, tokens);
|
||||
}
|
||||
|
||||
// Fall back to English by default if we can't find the key
|
||||
found = FindTranslation(xmlSource, new CultureInfo("en-US"), area, key);
|
||||
if (found != null)
|
||||
return ParseTokens(found.Value, tokens);
|
||||
|
||||
// If it can't be found in either file, fall back to the default, showing just the key in square brackets
|
||||
// NOTE: Based on how legacy works, the default text does not contain the area, just the key
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
private XElement FindTranslation(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo culture, string area, string key)
|
||||
{
|
||||
var cultureSource = xmlSource[culture].Value;
|
||||
|
||||
var xpath = area.IsNullOrWhiteSpace()
|
||||
? string.Format("//key [@alias = '{0}']", key)
|
||||
: string.Format("//area [@alias = '{0}']/key [@alias = '{1}']", area, key);
|
||||
|
||||
var found = cultureSource.XPathSelectElement(xpath);
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the tokens in the value
|
||||
/// </summary>
|
||||
@@ -303,11 +364,26 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
value = value.Replace(string.Format("{0}{1}{0}", "%", token.Key), token.Value);
|
||||
value = value.Replace(string.Concat("%", token.Key, "%"), token.Value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public IDictionary<string, IDictionary<string, string>> GetAllStoredValuesByAreaAndAlias(CultureInfo culture)
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException("culture");
|
||||
|
||||
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
if (_dictionarySource.ContainsKey(culture) == false)
|
||||
{
|
||||
_logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture);
|
||||
return new Dictionary<string, IDictionary<string, string>>(0);
|
||||
}
|
||||
|
||||
return _dictionarySource[culture];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault()
|
||||
return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name),
|
||||
GetQuotedTableName(index.TableName), columns);
|
||||
}
|
||||
|
||||
|
||||
public override string GetSpecialDbType(SpecialDbTypes dbTypes)
|
||||
{
|
||||
if (dbTypes == SpecialDbTypes.NVARCHARMAX) // SqlCE does not have nvarchar(max) for now
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
|
||||
// read properties count
|
||||
var pcount = PrimitiveSerializer.Int32.ReadFrom(stream);
|
||||
|
||||
var dict = new Dictionary<string, PropertyData[]>(pcount,StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
// read each property
|
||||
for (var i = 0; i < pcount; i++)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
for (var j = 0; j < vcount; j++)
|
||||
{
|
||||
var pdata = new PropertyData();
|
||||
pdatas[j] =pdata;
|
||||
pdatas[j] = pdata;
|
||||
|
||||
// everything that can be null is read/written as object
|
||||
// even though - culture and segment should never be null here, as 'null' represents
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -9,7 +9,6 @@ using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Querying;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
|
||||
using Umbraco.Cms.Persistence.SqlCe;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
@@ -19,7 +18,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
protected Lazy<ISqlContext> MockSqlContext()
|
||||
{
|
||||
var sqlContext = Mock.Of<ISqlContext>();
|
||||
var syntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings()));
|
||||
var syntax = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings()));
|
||||
Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(syntax);
|
||||
return new Lazy<ISqlContext>(() => sqlContext);
|
||||
}
|
||||
@@ -36,7 +35,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
_mapperCollection = mapperCollection.Object;
|
||||
}
|
||||
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings()));
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings()));
|
||||
private readonly CachedExpression _cachedExpression;
|
||||
private readonly IMapperCollection _mapperCollection;
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Umbraco.Tests.Benchmarks")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Umbraco.Tests.Benchmarks")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("3a33adc9-c6c0-4db1-a613-a9af0210df3d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,4 +1,4 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -6,7 +6,7 @@ using NPoco;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
|
||||
using Umbraco.Cms.Persistence.SqlCe;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var mappers = new NPoco.MapperCollection( );
|
||||
var factory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, mappers).Init());
|
||||
|
||||
SqlContext = new SqlContext(new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())), DatabaseType.SQLCe, factory);
|
||||
SqlContext = new SqlContext(new SqlServerSyntaxProvider(Options.Create(new GlobalSettings())), DatabaseType.SQLCe, factory);
|
||||
SqlTemplates = new SqlTemplates(SqlContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>8</LangVersion>
|
||||
<OutputType>Exe</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="CtorInvokeBenchmarks.cs.bak" />
|
||||
<None Remove="ReflectionUtilities-Unused.cs.bak" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Persistence.SqlCe\Umbraco.Persistence.SqlCe.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet">
|
||||
@@ -27,10 +25,7 @@
|
||||
<PackageReference Include="Moq">
|
||||
<Version>4.16.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.2.231403">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -260,8 +260,8 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Mapping
|
||||
}
|
||||
|
||||
Assert.AreEqual(contentType.CompositionPropertyGroups.Count(), invariantContent.Tabs.Count() - 1);
|
||||
Assert.IsTrue(invariantContent.Tabs.Any(x => x.Label == _localizedTextService.Localize("general/properties")));
|
||||
Assert.AreEqual(2, invariantContent.Tabs.Where(x => x.Label == _localizedTextService.Localize("general/properties")).SelectMany(x => x.Properties.Where(p => p.Alias.StartsWith("_umb_") == false)).Count());
|
||||
Assert.IsTrue(invariantContent.Tabs.Any(x => x.Label == _localizedTextService.Localize("general","properties")));
|
||||
Assert.AreEqual(2, invariantContent.Tabs.Where(x => x.Label == _localizedTextService.Localize("general","properties")).SelectMany(x => x.Properties.Where(p => p.Alias.StartsWith("_umb_") == false)).Count());
|
||||
}
|
||||
|
||||
private void AssertBasics(ContentItemDisplay result, IContent content)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NUnit.Framework;
|
||||
@@ -10,7 +12,9 @@ using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Tests.Integration.TestServerTest;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Website.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing
|
||||
{
|
||||
@@ -44,6 +48,24 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing
|
||||
// Assert
|
||||
Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Plugin_Controller_Routes_By_Area()
|
||||
{
|
||||
// Create URL manually, because PrepareSurfaceController URl will prepare whatever the controller is routed as
|
||||
Type controllerType = typeof(TestPluginController);
|
||||
var pluginAttribute = CustomAttributeExtensions.GetCustomAttribute<PluginControllerAttribute>(controllerType, false);
|
||||
var controllerName = ControllerExtensions.GetControllerName(controllerType);
|
||||
string url = $"/umbraco/{pluginAttribute?.AreaName}/{controllerName}";
|
||||
PrepareUrl(url);
|
||||
|
||||
HttpResponseMessage response = await Client.GetAsync(url);
|
||||
|
||||
string body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Test controllers must be non-nested, else we need to jump through some hoops with custom
|
||||
@@ -61,4 +83,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing
|
||||
|
||||
public IActionResult News() => NoContent();
|
||||
}
|
||||
|
||||
[PluginController("TestArea")]
|
||||
public class TestPluginController : SurfaceController
|
||||
{
|
||||
public TestPluginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public IActionResult Index() => Ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors
|
||||
// editor wants ApplicationContext.Current.Services.TextService
|
||||
// (that should be fixed with proper injection)
|
||||
var textService = new Mock<ILocalizedTextService>();
|
||||
textService.Setup(x => x.Localize(It.IsAny<string>(), It.IsAny<CultureInfo>(), It.IsAny<IDictionary<string, string>>())).Returns("blah");
|
||||
textService.Setup(x => x.Localize(It.IsAny<string>(), It.IsAny<string>(),It.IsAny<CultureInfo>(), It.IsAny<IDictionary<string, string>>())).Returns("blah");
|
||||
|
||||
//// var appContext = new ApplicationContext(
|
||||
//// new DatabaseContext(TestObjects.GetIDatabaseFactoryMock(), logger, Mock.Of<IRuntimeState>(), Mock.Of<IMigrationEntryService>()),
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services
|
||||
private void MockObjects(out PropertyValidationService validationService, out IDataType dt)
|
||||
{
|
||||
var textService = new Mock<ILocalizedTextService>();
|
||||
textService.Setup(x => x.Localize(It.IsAny<string>(), Thread.CurrentThread.CurrentCulture, null)).Returns("Localized text");
|
||||
textService.Setup(x => x.Localize(It.IsAny<string>(),It.IsAny<string>(), Thread.CurrentThread.CurrentCulture, null)).Returns("Localized text");
|
||||
|
||||
var dataTypeService = new Mock<IDataTypeService>();
|
||||
IDataType dataType = Mock.Of<IDataType>(
|
||||
|
||||
@@ -9,6 +9,7 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions
|
||||
{
|
||||
|
||||
@@ -54,48 +54,60 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common
|
||||
Assert.AreEqual(cropperValue, obj);
|
||||
}
|
||||
|
||||
//// [TestCase(CropperJson1, CropperJson1, true)]
|
||||
//// [TestCase(CropperJson1, CropperJson2, false)]
|
||||
//// public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected)
|
||||
//// {
|
||||
//// try
|
||||
//// {
|
||||
//// var container = TestHelper.GetRegister();
|
||||
//// var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache);
|
||||
////
|
||||
//// composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
||||
////
|
||||
//// Current.Factory = composition.CreateFactory();
|
||||
////
|
||||
//// var logger = Mock.Of<ILogger>();
|
||||
//// var scheme = Mock.Of<IMediaPathScheme>();
|
||||
//// var shortStringHelper = Mock.Of<IShortStringHelper>();
|
||||
////
|
||||
//// var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), scheme, logger, shortStringHelper);
|
||||
////
|
||||
//// var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
//// new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSettings>(), Mock.Of<IDataTypeService>(), Mock.Of<ILocalizationService>(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of<ILocalizedTextService>())) { Id = 1 });
|
||||
////
|
||||
//// var factory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty<IPropertyValueConverter>()), dataTypeService);
|
||||
////
|
||||
//// var converter = new ImageCropperValueConverter();
|
||||
//// var result = converter.ConvertSourceToIntermediate(null, factory.CreatePropertyType("test", 1), val1, false); // does not use type for conversion
|
||||
////
|
||||
//// var resultShouldMatch = val2.DeserializeImageCropperValue();
|
||||
//// if (expected)
|
||||
//// {
|
||||
//// Assert.AreEqual(resultShouldMatch, result);
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// Assert.AreNotEqual(resultShouldMatch, result);
|
||||
//// }
|
||||
//// }
|
||||
//// finally
|
||||
//// {
|
||||
//// Current.Reset();
|
||||
//// }
|
||||
//// }
|
||||
// [TestCase(CropperJson1, CropperJson1, true)]
|
||||
// [TestCase(CropperJson1, CropperJson2, false)]
|
||||
// public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// var container = RegisterFactory.Create();
|
||||
// var composition = new Composition(container, new TypeLoader(), Mock.Of<IProfilingLogger>(), ComponentTests.MockRuntimeState(RuntimeLevel.Run));
|
||||
//
|
||||
// composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
||||
//
|
||||
// Current.Factory = composition.CreateFactory();
|
||||
//
|
||||
// var logger = Mock.Of<ILogger>();
|
||||
// var scheme = Mock.Of<IMediaPathScheme>();
|
||||
// var config = Mock.Of<IContentSection>();
|
||||
//
|
||||
// var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), config, scheme, logger);
|
||||
//
|
||||
// var imageCropperConfiguration = new ImageCropperConfiguration()
|
||||
// {
|
||||
// Crops = new[]
|
||||
// {
|
||||
// new ImageCropperConfiguration.Crop()
|
||||
// {
|
||||
// Alias = "thumb",
|
||||
// Width = 100,
|
||||
// Height = 100
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
// new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>(), Mock.Of<IDataTypeService>())) { Id = 1, Configuration = imageCropperConfiguration });
|
||||
//
|
||||
// var factory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty<IPropertyValueConverter>()), dataTypeService);
|
||||
//
|
||||
// var converter = new ImageCropperValueConverter();
|
||||
// var result = converter.ConvertSourceToIntermediate(null, factory.CreatePropertyType("test", 1), val1, false); // does not use type for conversion
|
||||
//
|
||||
// var resultShouldMatch = val2.DeserializeImageCropperValue();
|
||||
// if (expected)
|
||||
// {
|
||||
// Assert.AreEqual(resultShouldMatch, result);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Assert.AreNotEqual(resultShouldMatch, result);
|
||||
// }
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// Current.Reset();
|
||||
// }
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void GetCropUrl_CropAliasTest()
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
|
||||
var globalSettings = new GlobalSettings();
|
||||
var nuCacheSettings = new NuCacheSettings();
|
||||
|
||||
|
||||
// at last, create the complete NuCache snapshot service!
|
||||
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
|
||||
_snapshotService = new PublishedSnapshotService(
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.ActionResults
|
||||
{
|
||||
public class UmbracoNotificationSuccessResponse : OkObjectResult
|
||||
{
|
||||
public UmbracoNotificationSuccessResponse(string successMessage) : base(null)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = successMessage
|
||||
};
|
||||
notificationModel.AddSuccessNotification(successMessage, string.Empty);
|
||||
|
||||
Value = notificationModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
else
|
||||
{
|
||||
AddModelErrors(result);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return new ValidationErrorResult(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,12 +383,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var code = await _userManager.GeneratePasswordResetTokenAsync(identityUser);
|
||||
var callbackUrl = ConstructCallbackUrl(identityUser.Id, code);
|
||||
|
||||
var message = _textService.Localize("login/resetPasswordEmailCopyFormat",
|
||||
var message = _textService.Localize("login","resetPasswordEmailCopyFormat",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, _textService, _globalSettings),
|
||||
new[] { identityUser.UserName, callbackUrl });
|
||||
|
||||
var subject = _textService.Localize("login/resetPasswordEmailCopySubject",
|
||||
var subject = _textService.Localize("login","resetPasswordEmailCopySubject",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, _textService, _globalSettings));
|
||||
|
||||
@@ -445,11 +445,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return BadRequest("Invalid code");
|
||||
}
|
||||
|
||||
var subject = _textService.Localize("login/mfaSecurityCodeSubject",
|
||||
var subject = _textService.Localize("login","mfaSecurityCodeSubject",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(user.Culture, _textService, _globalSettings));
|
||||
|
||||
var message = _textService.Localize("login/mfaSecurityCodeMessage",
|
||||
var message = _textService.Localize("login","mfaSecurityCodeMessage",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(user.Culture, _textService, _globalSettings),
|
||||
new[] { code });
|
||||
@@ -474,7 +474,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return new ValidationErrorResult(ModelState);
|
||||
}
|
||||
|
||||
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
|
||||
@@ -335,7 +335,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
//Add error and redirect for it to be displayed
|
||||
TempData[ViewDataExtensions.TokenPasswordResetCode] = new[] { _textService.Localize("login/resetCodeExpired") };
|
||||
TempData[ViewDataExtensions.TokenPasswordResetCode] = new[] { _textService.Localize("login","resetCodeExpired") };
|
||||
return RedirectToLocal(Url.Action(nameof(Default), this.GetControllerName()));
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
// Sign in the user with this external login provider (which auto links, etc...)
|
||||
var result = await _signInManager.ExternalLoginSignInAsync(loginInfo, isPersistent: false);
|
||||
|
||||
|
||||
var errors = new List<string>();
|
||||
|
||||
if (result == Microsoft.AspNetCore.Identity.SignInResult.Success)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Web.BackOffice.ActionResults;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -11,5 +17,55 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[AppendCurrentEventMessages]
|
||||
public abstract class BackOfficeNotificationsController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
/// <summary>
|
||||
/// returns a 200 OK response with a notification message
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
protected OkObjectResult Ok(string message)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = message
|
||||
};
|
||||
notificationModel.AddSuccessNotification(message, string.Empty);
|
||||
|
||||
return new OkObjectResult(notificationModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to ensure that the error message is an error notification message
|
||||
/// </summary>
|
||||
/// <param name="errorMessage"></param>
|
||||
/// <returns></returns>
|
||||
protected override ActionResult ValidationProblem(string errorMessage)
|
||||
=> ValidationProblem(errorMessage, string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a notofication validation problem with a header and message
|
||||
/// </summary>
|
||||
/// <param name="errorHeader"></param>
|
||||
/// <param name="errorMessage"></param>
|
||||
/// <returns></returns>
|
||||
protected ActionResult ValidationProblem(string errorHeader, string errorMessage)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
{
|
||||
Message = errorMessage
|
||||
};
|
||||
notificationModel.AddErrorNotification(errorHeader, errorMessage);
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to ensure that all queued notifications are sent to the back office
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public override ActionResult ValidationProblem()
|
||||
// returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
=> new ValidationErrorResult(new SimpleNotificationModel());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,9 +86,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
view.Content = display.Content;
|
||||
var result = _fileService.CreatePartialView(view, display.Snippet, currentUser.Id);
|
||||
if (result.Success)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
{
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
case Constants.Trees.PartialViewMacros:
|
||||
var viewMacro = new PartialView(PartialViewType.PartialViewMacro, display.VirtualPath);
|
||||
@@ -97,7 +101,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (resultMacro.Success)
|
||||
return Ok();
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(resultMacro.Exception.Message);
|
||||
return ValidationProblem(resultMacro.Exception.Message);
|
||||
|
||||
case Constants.Trees.Scripts:
|
||||
var script = new Script(display.VirtualPath);
|
||||
@@ -123,7 +127,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (string.IsNullOrWhiteSpace(parentId)) throw new ArgumentException("Value cannot be null or whitespace.", "parentId");
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
|
||||
if (name.ContainsAny(Path.GetInvalidPathChars())) {
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(_localizedTextService.Localize("codefile/createFolderIllegalChars"));
|
||||
return ValidationProblem(_localizedTextService.Localize("codefile", "createFolderIllegalChars"));
|
||||
}
|
||||
|
||||
// if the parentId is root (-1) then we just need an empty string as we are
|
||||
@@ -418,8 +422,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
display.AddErrorNotification(
|
||||
_localizedTextService.Localize("speechBubbles/partialViewErrorHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/partialViewErrorText"));
|
||||
_localizedTextService.Localize("speechBubbles", "partialViewErrorHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "partialViewErrorText"));
|
||||
break;
|
||||
|
||||
case Constants.Trees.PartialViewMacros:
|
||||
@@ -433,8 +437,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
display.AddErrorNotification(
|
||||
_localizedTextService.Localize("speechBubbles/partialViewErrorHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/partialViewErrorText"));
|
||||
_localizedTextService.Localize("speechBubbles", "partialViewErrorHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "partialViewErrorText"));
|
||||
break;
|
||||
|
||||
case Constants.Trees.Scripts:
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
new ContentVariantDisplay
|
||||
{
|
||||
CreateDate = DateTime.Now,
|
||||
Name = _localizedTextService.Localize("general/recycleBin")
|
||||
Name = _localizedTextService.Localize("general","recycleBin")
|
||||
}
|
||||
},
|
||||
ContentApps = apps
|
||||
@@ -417,16 +417,65 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var emptyContent = _contentService.Create("", parentId, contentType.Alias, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
var mapped = MapToDisplay(emptyContent);
|
||||
|
||||
return CleanContentItemDisplay(mapped);
|
||||
}
|
||||
|
||||
private ContentItemDisplay CleanContentItemDisplay(ContentItemDisplay display)
|
||||
{
|
||||
// translate the content type name if applicable
|
||||
mapped.ContentTypeName = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.ContentTypeName);
|
||||
display.ContentTypeName = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, display.ContentTypeName);
|
||||
// if your user type doesn't have access to the Settings section it would not get this property mapped
|
||||
if (mapped.DocumentType != null)
|
||||
mapped.DocumentType.Name = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.DocumentType.Name);
|
||||
if (display.DocumentType != null)
|
||||
display.DocumentType.Name = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, display.DocumentType.Name);
|
||||
|
||||
//remove the listview app if it exists
|
||||
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();
|
||||
display.ContentApps = display.ContentApps.Where(x => x.Alias != "umbListView").ToList();
|
||||
|
||||
return mapped;
|
||||
return display;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty <see cref="ContentItemDisplay"/> for each content type in the IEnumerable, all with the same parent ID
|
||||
/// </summary>
|
||||
/// <remarks>Will attempt to re-use the same permissions for every content as long as the path and user are the same</remarks>
|
||||
/// <param name="contentTypes"></param>
|
||||
/// <param name="parentId"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<ContentItemDisplay> GetEmpties(IEnumerable<IContentType> contentTypes, int parentId)
|
||||
{
|
||||
var result = new List<ContentItemDisplay>();
|
||||
var backOfficeSecurity = _backofficeSecurityAccessor.BackOfficeSecurity;
|
||||
|
||||
var userId = backOfficeSecurity.GetUserId().ResultOr(0);
|
||||
var currentUser = backOfficeSecurity.CurrentUser;
|
||||
// We know that if the ID is less than 0 the parent is null.
|
||||
// Since this is called with parent ID it's safe to assume that the parent is the same for all the content types.
|
||||
var parent = parentId > 0 ? _contentService.GetById(parentId) : null;
|
||||
// Since the parent is the same and the path used to get permissions is based on the parent we only have to do it once
|
||||
var path = parent == null ? "-1" : parent.Path;
|
||||
var permissions = new Dictionary<string, EntityPermissionSet>
|
||||
{
|
||||
[path] = _userService.GetPermissionsForPath(currentUser, path)
|
||||
};
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
var emptyContent = _contentService.Create("", parentId, contentType, userId);
|
||||
|
||||
var mapped = MapToDisplay(emptyContent, context =>
|
||||
{
|
||||
// Since the permissions depend on current user and path, we add both of these to context as well,
|
||||
// that way we can compare the path and current user when mapping, if they're the same just take permissions
|
||||
// and skip getting them again, in theory they should always be the same, but better safe than sorry.,
|
||||
context.Items["Parent"] = parent;
|
||||
context.Items["CurrentUser"] = currentUser;
|
||||
context.Items["Permissions"] = permissions;
|
||||
});
|
||||
result.Add(CleanContentItemDisplay(mapped));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -437,22 +486,9 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[OutgoingEditorModelEvent]
|
||||
public ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeys([FromQuery] Guid[] contentTypeKeys, [FromQuery] int parentId)
|
||||
{
|
||||
var result = new Dictionary<Guid, ContentItemDisplay>();
|
||||
|
||||
using var scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
var contentTypes = _contentTypeService.GetAll(contentTypeKeys).ToList();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
if (contentType is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
result.Add(contentType.Key, GetEmptyInner(contentType, parentId));
|
||||
}
|
||||
|
||||
return result;
|
||||
return GetEmpties(contentTypes, parentId).ToDictionary(x => x.ContentTypeKey);
|
||||
}
|
||||
|
||||
[OutgoingEditorModelEvent]
|
||||
@@ -607,7 +643,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (!EnsureUniqueName(name, content, nameof(name)))
|
||||
{
|
||||
return new ValidationErrorResult(ModelState.ToErrorDictionary());
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
var blueprint = _contentService.CreateContentFromBlueprint(content, name, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
@@ -616,8 +652,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddSuccessNotification(
|
||||
_localizedTextService.Localize("blueprints/createdBlueprintHeading"),
|
||||
_localizedTextService.Localize("blueprints/createdBlueprintMessage", new[] { content.Name })
|
||||
_localizedTextService.Localize("blueprints", "createdBlueprintHeading"),
|
||||
_localizedTextService.Localize("blueprints", "createdBlueprintMessage", new[] { content.Name })
|
||||
);
|
||||
|
||||
return notificationModel;
|
||||
@@ -628,7 +664,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var existing = _contentService.GetBlueprintsForContentTypes(content.ContentTypeId);
|
||||
if (existing.Any(x => x.Name == name && x.Id != content.Id))
|
||||
{
|
||||
ModelState.AddModelError(modelName, _localizedTextService.Localize("blueprints/duplicateBlueprintMessage"));
|
||||
ModelState.AddModelError(modelName, _localizedTextService.Localize("blueprints", "duplicateBlueprintMessage"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -714,8 +750,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
// ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
|
||||
// add the model state to the outgoing object and throw a validation message
|
||||
var forDisplay = mapToDisplay(contentItem.PersistedContent);
|
||||
forDisplay.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(forDisplay);
|
||||
return ValidationProblem(forDisplay, ModelState);
|
||||
}
|
||||
|
||||
// if there's only one variant and the model state is not valid we cannot publish so change it to save
|
||||
@@ -795,15 +830,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var variantName = GetVariantName(culture, segment);
|
||||
|
||||
AddSuccessNotification(notifications, culture, segment,
|
||||
_localizedTextService.Localize("speechBubbles/editContentSendToPublish"),
|
||||
_localizedTextService.Localize("speechBubbles/editVariantSendToPublishText", new[] { variantName }));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentSendToPublish"),
|
||||
_localizedTextService.Localize("speechBubbles", "editVariantSendToPublishText", new[] { variantName }));
|
||||
}
|
||||
}
|
||||
else if (ModelState.IsValid)
|
||||
{
|
||||
globalNotifications.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentSendToPublish"),
|
||||
_localizedTextService.Localize("speechBubbles/editContentSendToPublishText"));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentSendToPublish"),
|
||||
_localizedTextService.Localize("speechBubbles", "editContentSendToPublishText"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -820,8 +855,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (!await ValidatePublishBranchPermissionsAsync(contentItem))
|
||||
{
|
||||
globalNotifications.AddErrorNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/invalidPublishBranchPermissions"));
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "invalidPublishBranchPermissions"));
|
||||
wasCancelled = false;
|
||||
break;
|
||||
}
|
||||
@@ -836,8 +871,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (!await ValidatePublishBranchPermissionsAsync(contentItem))
|
||||
{
|
||||
globalNotifications.AddErrorNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/invalidPublishBranchPermissions"));
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "invalidPublishBranchPermissions"));
|
||||
wasCancelled = false;
|
||||
break;
|
||||
}
|
||||
@@ -866,8 +901,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//lastly, if it is not valid, add the model state to the outgoing object and throw a 400
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
display.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(display);
|
||||
return ValidationProblem(display, ModelState);
|
||||
}
|
||||
|
||||
if (wasCancelled)
|
||||
@@ -878,7 +912,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//If the item is new and the operation was cancelled, we need to return a different
|
||||
// status code so the UI can handle it since it won't be able to redirect since there
|
||||
// is no Id to redirect to!
|
||||
return new ValidationErrorResult(display);
|
||||
return ValidationProblem(display);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,7 +967,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//if there's more than 1 variant, then we need to add the culture specific error
|
||||
//messages based on the variants in error so that the messages show in the publish/save dialog
|
||||
if (variants.Count > 1)
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "publish/contentPublishedFailedByMissingName");
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "publish","contentPublishedFailedByMissingName");
|
||||
else
|
||||
return false; //It's invariant and is missing critical data, it cannot be saved
|
||||
}
|
||||
@@ -970,15 +1004,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// <param name="variantCount"></param>
|
||||
/// <param name="notifications"></param>
|
||||
/// <param name="globalNotifications"></param>
|
||||
/// <param name="invariantSavedLocalizationKey"></param>
|
||||
/// <param name="variantSavedLocalizationKey"></param>
|
||||
/// <param name="invariantSavedLocalizationAlias"></param>
|
||||
/// <param name="variantSavedLocalizationAlias"></param>
|
||||
/// <param name="wasCancelled"></param>
|
||||
/// <remarks>
|
||||
/// Method is used for normal Saving and Scheduled Publishing
|
||||
/// </remarks>
|
||||
private void SaveAndNotify(ContentItemSave contentItem, Func<IContent, OperationResult> saveMethod, int variantCount,
|
||||
Dictionary<string, SimpleNotificationModel> notifications, SimpleNotificationModel globalNotifications,
|
||||
string invariantSavedLocalizationKey, string variantSavedLocalizationKey, string cultureForInvariantErrors,
|
||||
string invariantSavedLocalizationAlias, string variantSavedLocalizationAlias, string cultureForInvariantErrors,
|
||||
out bool wasCancelled)
|
||||
{
|
||||
var saveResult = saveMethod(contentItem.PersistedContent);
|
||||
@@ -998,15 +1032,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var variantName = GetVariantName(culture, segment);
|
||||
|
||||
AddSuccessNotification(notifications, culture, segment,
|
||||
_localizedTextService.Localize("speechBubbles/editContentSavedHeader"),
|
||||
_localizedTextService.Localize(variantSavedLocalizationKey, new[] { variantName }));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentSavedHeader"),
|
||||
_localizedTextService.Localize(null,variantSavedLocalizationAlias, new[] { variantName }));
|
||||
}
|
||||
}
|
||||
else if (ModelState.IsValid)
|
||||
{
|
||||
globalNotifications.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentSavedHeader"),
|
||||
_localizedTextService.Localize(invariantSavedLocalizationKey));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentSavedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles",invariantSavedLocalizationAlias));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1133,7 +1167,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//can't continue, a mandatory variant is not published and not scheduled for publishing
|
||||
// TODO: Add segment
|
||||
AddVariantValidationError(culture, null, "speechBubbles/scheduleErrReleaseDate2");
|
||||
AddVariantValidationError(culture, null, "speechBubbles", "scheduleErrReleaseDate2");
|
||||
isValid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1141,7 +1175,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//can't continue, a mandatory variant is not published and it's scheduled for publishing after a non-mandatory
|
||||
// TODO: Add segment
|
||||
AddVariantValidationError(culture, null, "speechBubbles/scheduleErrReleaseDate3");
|
||||
AddVariantValidationError(culture, null, "speechBubbles", "scheduleErrReleaseDate3");
|
||||
isValid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1155,7 +1189,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//1) release date cannot be less than now
|
||||
if (variant.ReleaseDate.HasValue && variant.ReleaseDate < DateTime.Now)
|
||||
{
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles/scheduleErrReleaseDate1");
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles", "scheduleErrReleaseDate1");
|
||||
isValid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1163,7 +1197,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//2) expire date cannot be less than now
|
||||
if (variant.ExpireDate.HasValue && variant.ExpireDate < DateTime.Now)
|
||||
{
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles/scheduleErrExpireDate1");
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles", "scheduleErrExpireDate1");
|
||||
isValid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1171,7 +1205,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//3) expire date cannot be less than release date
|
||||
if (variant.ExpireDate.HasValue && variant.ReleaseDate.HasValue && variant.ExpireDate <= variant.ReleaseDate)
|
||||
{
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles/scheduleErrExpireDate2");
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles", "scheduleErrExpireDate2");
|
||||
isValid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1399,19 +1433,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (r.publishing && !r.isValid)
|
||||
{
|
||||
//flagged for publishing but the mandatory culture is invalid
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "publish/contentPublishedFailedReqCultureValidationError");
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "publish", "contentPublishedFailedReqCultureValidationError");
|
||||
canPublish = false;
|
||||
}
|
||||
else if (r.publishing && r.isValid && firstInvalidMandatoryCulture != null)
|
||||
{
|
||||
//in this case this culture also cannot be published because another mandatory culture is invalid
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "publish/contentPublishedFailedReqCultureValidationError", firstInvalidMandatoryCulture);
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "publish", "contentPublishedFailedReqCultureValidationError", firstInvalidMandatoryCulture);
|
||||
canPublish = false;
|
||||
}
|
||||
else if (!r.publishing)
|
||||
{
|
||||
//cannot continue publishing since a required culture that is not currently being published isn't published
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "speechBubbles/contentReqCulturePublishError");
|
||||
AddVariantValidationError(r.model.Culture, r.model.Segment, "speechBubbles", "contentReqCulturePublishError");
|
||||
canPublish = false;
|
||||
}
|
||||
}
|
||||
@@ -1436,7 +1470,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var valid = persistentContent.PublishCulture(CultureImpact.Explicit(variant.Culture, defaultCulture.InvariantEquals(variant.Culture)));
|
||||
if (!valid)
|
||||
{
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles/contentCultureValidationError");
|
||||
AddVariantValidationError(variant.Culture, variant.Segment, "speechBubbles", "contentCultureValidationError");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1453,12 +1487,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// <param name="cultureToken">
|
||||
/// The culture used in the localization message, null by default which means <see cref="culture"/> will be used.
|
||||
/// </param>
|
||||
private void AddVariantValidationError(string culture, string segment, string localizationKey, string cultureToken = null)
|
||||
private void AddVariantValidationError(string culture, string segment, string localizationArea,string localizationAlias, string cultureToken = null)
|
||||
{
|
||||
var cultureToUse = cultureToken ?? culture;
|
||||
var variantName = GetVariantName(cultureToUse, segment);
|
||||
|
||||
var errMsg = _localizedTextService.Localize(localizationKey, new[] { variantName });
|
||||
var errMsg = _localizedTextService.Localize(localizationArea, localizationAlias, new[] { variantName });
|
||||
|
||||
ModelState.AddVariantValidationError(culture, segment, errMsg);
|
||||
}
|
||||
@@ -1508,7 +1542,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
AddMessageForPublishStatus(new[] { publishResult }, notificationModel);
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
return ValidationProblem(notificationModel);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
@@ -1558,9 +1592,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var moveResult = _contentService.MoveToRecycleBin(foundContent, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
if (moveResult.Success == false)
|
||||
{
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1568,9 +1600,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var deleteResult = _contentService.Delete(foundContent, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
if (deleteResult.Success == false)
|
||||
{
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1591,7 +1621,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
_contentService.EmptyRecycleBin(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty"));
|
||||
return Ok(_localizedTextService.Localize("defaultdialogs", "recycleBinIsEmpty"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1628,7 +1658,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
_logger.LogWarning("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
// TODO: Now you can cancel sorting, does the event messages bubble up automatically?
|
||||
return new ValidationErrorResult("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
return ValidationProblem("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
}
|
||||
|
||||
return Ok();
|
||||
@@ -1727,13 +1757,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (!unpublishResult.Success)
|
||||
{
|
||||
AddCancelMessage(content);
|
||||
return new ValidationErrorResult(content);
|
||||
return ValidationProblem(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
content.AddSuccessNotification(
|
||||
_localizedTextService.Localize("content/unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles/contentUnpublished"));
|
||||
_localizedTextService.Localize("content", "unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles", "contentUnpublished"));
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -1758,8 +1788,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (results.Any(x => x.Value.Result == PublishResultType.SuccessUnpublishMandatoryCulture))
|
||||
{
|
||||
content.AddSuccessNotification(
|
||||
_localizedTextService.Localize("content/unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles/contentMandatoryCultureUnpublished"));
|
||||
_localizedTextService.Localize("content", "unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles", "contentMandatoryCultureUnpublished"));
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -1767,8 +1797,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
foreach (var r in results)
|
||||
{
|
||||
content.AddSuccessNotification(
|
||||
_localizedTextService.Localize("content/unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles/contentCultureUnpublished", new[] { _allLangs.Value[r.Key].CultureName }));
|
||||
_localizedTextService.Localize("conten", "unpublish"),
|
||||
_localizedTextService.Localize("speechBubbles", "contentCultureUnpublished", new[] { _allLangs.Value[r.Key].CultureName }));
|
||||
}
|
||||
return content;
|
||||
|
||||
@@ -1799,7 +1829,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
return new ValidationErrorResult(_localizedTextService.Localize("assignDomain/invalidDomain"));
|
||||
return ValidationProblem(_localizedTextService.Localize("assignDomain", "invalidDomain"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1949,7 +1979,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
foreach (var (culture, segment) in variantErrors)
|
||||
{
|
||||
AddVariantValidationError(culture, segment, "speechBubbles/contentCultureValidationError");
|
||||
AddVariantValidationError(culture, segment, "speechBubbles", "contentCultureValidationError");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2069,8 +2099,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//cannot move if the content item is not allowed at the root
|
||||
if (toMove.ContentType.AllowedAsRoot == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(
|
||||
_localizedTextService.Localize("moveOrCopy/notAllowedAtRoot"));
|
||||
return ValidationProblem(
|
||||
_localizedTextService.Localize("moveOrCopy", "notAllowedAtRoot"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2086,15 +2116,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (parentContentType.AllowedContentTypes.Select(x => x.Id).ToArray()
|
||||
.Any(x => x.Value == toMove.ContentType.Id) == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(
|
||||
_localizedTextService.Localize("moveOrCopy/notAllowedByContentType"));
|
||||
return ValidationProblem(
|
||||
_localizedTextService.Localize("moveOrCopy", "notAllowedByContentType"));
|
||||
}
|
||||
|
||||
// Check on paths
|
||||
if ($",{parent.Path},".IndexOf($",{toMove.Id},", StringComparison.Ordinal) > -1)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(
|
||||
_localizedTextService.Localize("moveOrCopy/notAllowedByPath"));
|
||||
return ValidationProblem(
|
||||
_localizedTextService.Localize("moveOrCopy", "notAllowedByPath"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2163,16 +2193,16 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//either invariant single publish, or bulk publish where all statuses are already published
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/editContentPublishedText"));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "editContentPublishedText"));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var c in successfulCultures)
|
||||
{
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/editVariantPublishedText", new[] { _allLangs.Value[c].CultureName }));
|
||||
_localizedTextService.Localize("speechBubbles", "editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "editVariantPublishedText", new[] { _allLangs.Value[c].CultureName }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2188,20 +2218,20 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (successfulCultures == null)
|
||||
{
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "editContentPublishedHeader"),
|
||||
totalStatusCount > 1
|
||||
? _localizedTextService.Localize("speechBubbles/editMultiContentPublishedText", new[] { itemCount.ToInvariantString() })
|
||||
: _localizedTextService.Localize("speechBubbles/editContentPublishedText"));
|
||||
? _localizedTextService.Localize("speechBubbles", "editMultiContentPublishedText", new[] { itemCount.ToInvariantString() })
|
||||
: _localizedTextService.Localize("speechBubbles", "editContentPublishedText"));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var c in successfulCultures)
|
||||
{
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editContentPublishedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "editContentPublishedHeader"),
|
||||
totalStatusCount > 1
|
||||
? _localizedTextService.Localize("speechBubbles/editMultiVariantPublishedText", new[] { itemCount.ToInvariantString(), _allLangs.Value[c].CultureName })
|
||||
: _localizedTextService.Localize("speechBubbles/editVariantPublishedText", new[] { _allLangs.Value[c].CultureName }));
|
||||
? _localizedTextService.Localize("speechBubbles", "editMultiVariantPublishedText", new[] { itemCount.ToInvariantString(), _allLangs.Value[c].CultureName })
|
||||
: _localizedTextService.Localize("speechBubbles", "editVariantPublishedText", new[] { _allLangs.Value[c].CultureName }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2211,8 +2241,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//TODO: This doesn't take into account variations with the successfulCultures param
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedByParent",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedByParent",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
break;
|
||||
@@ -2220,7 +2250,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//TODO: This doesn't take into account variations with the successfulCultures param
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
AddCancelMessage(display, message: "publish/contentPublishedFailedByEvent", messageParams: new[] { names });
|
||||
AddCancelMessage(display, "publish","contentPublishedFailedByEvent", messageParams: new[] { names });
|
||||
}
|
||||
break;
|
||||
case PublishResultType.FailedPublishAwaitingRelease:
|
||||
@@ -2228,8 +2258,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//TODO: This doesn't take into account variations with the successfulCultures param
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedAwaitingRelease",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedAwaitingRelease",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
break;
|
||||
@@ -2238,8 +2268,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//TODO: This doesn't take into account variations with the successfulCultures param
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedExpired",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedExpired",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
break;
|
||||
@@ -2248,8 +2278,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//TODO: This doesn't take into account variations with the successfulCultures param
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedIsTrashed",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedIsTrashed",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
break;
|
||||
@@ -2259,8 +2289,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"'{x.Content.Name}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedInvalid",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedInvalid",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
else
|
||||
@@ -2269,8 +2299,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"'{(x.Content.ContentType.VariesByCulture() ? x.Content.GetCultureName(c) : x.Content.Name)}'"));
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize("publish/contentPublishedFailedInvalid",
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
_localizedTextService.Localize("publish", "contentPublishedFailedInvalid",
|
||||
new[] { names }).Trim());
|
||||
}
|
||||
}
|
||||
@@ -2278,7 +2308,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
break;
|
||||
case PublishResultType.FailedPublishMandatoryCultureMissing:
|
||||
display.AddWarningNotification(
|
||||
_localizedTextService.Localize("publish"),
|
||||
_localizedTextService.Localize(null,"publish"),
|
||||
"publish/contentPublishedFailedByCulture");
|
||||
break;
|
||||
default:
|
||||
@@ -2292,12 +2322,22 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
private ContentItemDisplay MapToDisplay(IContent content)
|
||||
{
|
||||
var display = _umbracoMapper.Map<ContentItemDisplay>(content, context =>
|
||||
private ContentItemDisplay MapToDisplay(IContent content) =>
|
||||
MapToDisplay(content, context =>
|
||||
{
|
||||
context.Items["CurrentUser"] = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Used to map an <see cref="IContent"/> instance to a <see cref="ContentItemDisplay"/> and ensuring AllowPreview is set correctly.
|
||||
/// Also allows you to pass in an action for the mapper context where you can pass additional information on to the mapper.
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="contextOptions"></param>
|
||||
/// <returns></returns>
|
||||
private ContentItemDisplay MapToDisplay(IContent content, Action<MapperContext> contextOptions)
|
||||
{
|
||||
var display = _umbracoMapper.Map<ContentItemDisplay>(content, contextOptions);
|
||||
display.AllowPreview = display.AllowPreview && content.Trashed == false && content.ContentType.IsElement == false;
|
||||
return display;
|
||||
}
|
||||
@@ -2403,8 +2443,6 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (rollbackResult.Success)
|
||||
return Ok();
|
||||
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
|
||||
switch (rollbackResult.Result)
|
||||
{
|
||||
case OperationResultType.Failed:
|
||||
@@ -2412,22 +2450,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
case OperationResultType.FailedExceptionThrown:
|
||||
case OperationResultType.NoOperation:
|
||||
default:
|
||||
notificationModel.AddErrorNotification(
|
||||
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
null); // TODO: There is no specific failed to save error message AFAIK
|
||||
break;
|
||||
return ValidationProblem(_localizedTextService.Localize("speechBubbles", "operationFailedHeader"));
|
||||
case OperationResultType.FailedCancelledByEvent:
|
||||
notificationModel.AddErrorNotification(
|
||||
_localizedTextService.Localize("speechBubbles/operationCancelledHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/operationCancelledText"));
|
||||
break;
|
||||
return ValidationProblem(
|
||||
_localizedTextService.Localize("speechBubbles", "operationCancelledHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "operationCancelledText"));
|
||||
}
|
||||
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,15 +190,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// Adds a cancelled message to the display
|
||||
/// </summary>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="localizeHeader"></param>
|
||||
/// <param name="localizeMessage"></param>
|
||||
/// <param name="headerParams"></param>
|
||||
/// <param name="messageArea"></param>
|
||||
/// <param name="messageAlias"></param>
|
||||
/// <param name="messageParams"></param>
|
||||
protected void AddCancelMessage(INotificationModel display, string header = "speechBubbles/operationCancelledHeader", string message = "speechBubbles/operationCancelledText", bool localizeHeader = true,
|
||||
bool localizeMessage = true,
|
||||
string[] headerParams = null,
|
||||
protected void AddCancelMessage(
|
||||
INotificationModel display,
|
||||
string messageArea = "speechBubbles",
|
||||
string messageAlias ="operationCancelledText",
|
||||
string[] messageParams = null)
|
||||
{
|
||||
// if there's already a default event message, don't add our default one
|
||||
@@ -209,8 +207,29 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
display.AddWarningNotification(
|
||||
localizeHeader ? LocalizedTextService.Localize(header, headerParams) : header,
|
||||
localizeMessage ? LocalizedTextService.Localize(message, messageParams) : message);
|
||||
LocalizedTextService.Localize("speechBubbles", "operationCancelledHeader"),
|
||||
LocalizedTextService.Localize(messageArea, messageAlias, messageParams));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a cancelled message to the display
|
||||
/// </summary>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="headerArea"></param>
|
||||
/// <param name="headerAlias"></param>
|
||||
/// <param name="headerParams"></param>
|
||||
protected void AddCancelMessage(INotificationModel display, string message)
|
||||
{
|
||||
// if there's already a default event message, don't add our default one
|
||||
IEventMessagesFactory messages = EventMessages;
|
||||
if (messages != null && messages.GetOrDefault().GetAll().Any(x => x.IsDefaultEventMessage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
display.AddWarningNotification(LocalizedTextService.Localize("speechBubbles", "operationCancelledHeader"), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result); //return the id
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
|
||||
@@ -308,7 +308,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result); //return the id
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
|
||||
@@ -364,7 +364,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/contentTypeSavedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles","contentTypeSavedHeader"),
|
||||
string.Empty);
|
||||
|
||||
return display;
|
||||
@@ -612,8 +612,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
else
|
||||
{
|
||||
model.Notifications.Add(new BackOfficeNotification(
|
||||
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
_localizedTextService.Localize("media/disallowedFileType"),
|
||||
_localizedTextService.Localize("speechBubbles","operationFailedHeader"),
|
||||
_localizedTextService.Localize("media","disallowedFileType"),
|
||||
NotificationStyle.Warning));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Extensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
@@ -27,7 +25,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[PrefixlessBodyModelValidator]
|
||||
public abstract class ContentTypeControllerBase<TContentType> : UmbracoAuthorizedJsonController
|
||||
public abstract class ContentTypeControllerBase<TContentType> : BackOfficeNotificationsController
|
||||
where TContentType : class, IContentTypeComposition
|
||||
{
|
||||
private readonly EditorValidatorCollection _editorValidatorCollection;
|
||||
@@ -274,7 +272,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var exists = allAliases.InvariantContains(contentTypeSave.Alias);
|
||||
if (exists && (ctId == 0 || !ct.Alias.InvariantEquals(contentTypeSave.Alias)))
|
||||
{
|
||||
ModelState.AddModelError("Alias", LocalizedTextService.Localize("editcontenttype/aliasAlreadyExists"));
|
||||
ModelState.AddModelError("Alias", LocalizedTextService.Localize("editcontenttype", "aliasAlreadyExists"));
|
||||
}
|
||||
|
||||
// execute the external validators
|
||||
@@ -283,7 +281,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
var err = CreateModelStateValidationEror<TContentTypeSave, TContentTypeDisplay>(ctId, contentTypeSave, ct);
|
||||
return new ValidationErrorResult(err);
|
||||
return ValidationProblem(err);
|
||||
}
|
||||
|
||||
//filter out empty properties
|
||||
@@ -305,11 +303,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (Exception ex)
|
||||
{
|
||||
var responseEx = CreateInvalidCompositionResponseException<TContentTypeDisplay, TContentTypeSave, TPropertyType>(ex, contentTypeSave, ct, ctId);
|
||||
if (responseEx != null) return new ValidationErrorResult(responseEx);
|
||||
if (responseEx != null) return ValidationProblem(responseEx);
|
||||
}
|
||||
|
||||
var exResult = CreateCompositionValidationExceptionIfInvalid<TContentTypeSave, TPropertyType, TContentTypeDisplay>(contentTypeSave, ct);
|
||||
if (exResult != null) return new ValidationErrorResult(exResult);
|
||||
if (exResult != null) return ValidationProblem(exResult);
|
||||
|
||||
saveContentType(ct);
|
||||
|
||||
@@ -348,11 +346,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (responseEx is null)
|
||||
throw ex;
|
||||
|
||||
return new ValidationErrorResult(responseEx);
|
||||
return ValidationProblem(responseEx);
|
||||
}
|
||||
|
||||
var exResult = CreateCompositionValidationExceptionIfInvalid<TContentTypeSave, TPropertyType, TContentTypeDisplay>(contentTypeSave, newCt);
|
||||
if (exResult != null) return new ValidationErrorResult(exResult);
|
||||
if (exResult != null) return ValidationProblem(exResult);
|
||||
|
||||
//set id to null to ensure its handled as a new type
|
||||
contentTypeSave.Id = null;
|
||||
@@ -417,13 +415,9 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
case MoveOperationStatusType.FailedParentNotFound:
|
||||
return NotFound();
|
||||
case MoveOperationStatusType.FailedCancelledByEvent:
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
case MoveOperationStatusType.FailedNotAllowedByPath:
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(LocalizedTextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
return ValidationProblem(LocalizedTextService.Localize("moveOrCopy", "notAllowedByPath"));
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
@@ -458,13 +452,9 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
case MoveOperationStatusType.FailedParentNotFound:
|
||||
return NotFound();
|
||||
case MoveOperationStatusType.FailedCancelledByEvent:
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
case MoveOperationStatusType.FailedNotAllowedByPath:
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(LocalizedTextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
return ValidationProblem(LocalizedTextService.Localize("moveOrCopy", "notAllowedByPath"));
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
// so that is why it is being used here.
|
||||
ModelState.AddModelError("value", result.Errors.ToErrorMessage());
|
||||
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
//They've successfully set their password, we can now update their user account to be approved
|
||||
@@ -233,7 +233,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
// even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword
|
||||
var result = new ModelWithNotifications<string>(passwordChangeResult.Result.ResetPassword);
|
||||
result.AddSuccessNotification(_localizedTextService.Localize("user/password"), _localizedTextService.Localize("user/passwordChanged"));
|
||||
result.AddSuccessNotification(_localizedTextService.Localize("user","password"), _localizedTextService.Localize("user","passwordChanged"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError.ErrorMessage);
|
||||
}
|
||||
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
// TODO: Why is this necessary? This inherits from UmbracoAuthorizedApiController
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
@@ -20,6 +21,7 @@ using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Extensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
@@ -39,7 +41,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
private readonly IDashboardService _dashboardService;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
|
||||
private readonly IOptions<ContentDashboardSettings> _dashboardSettings;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DashboardController"/> with all its dependencies.
|
||||
/// </summary>
|
||||
@@ -49,7 +51,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
ILogger<DashboardController> logger,
|
||||
IDashboardService dashboardService,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
IShortStringHelper shortStringHelper)
|
||||
IShortStringHelper shortStringHelper,
|
||||
IOptions<ContentDashboardSettings> dashboardSettings)
|
||||
|
||||
{
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
@@ -58,6 +61,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
_dashboardService = dashboardService;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_dashboardSettings = dashboardSettings;
|
||||
}
|
||||
|
||||
//we have just one instance of HttpClient shared for the entire application
|
||||
@@ -65,7 +69,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
//we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side
|
||||
[ValidateAngularAntiForgeryToken]
|
||||
public async Task<JObject> GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/")
|
||||
public async Task<JObject> GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.com/")
|
||||
{
|
||||
var user = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
|
||||
var allowedSections = string.Join(",", user.AllowedSections);
|
||||
@@ -73,7 +77,14 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var version = _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild();
|
||||
var isAdmin = user.IsAdmin();
|
||||
|
||||
var url = string.Format(baseUrl + "{0}?section={0}&allowed={1}&lang={2}&version={3}&admin={4}", section, allowedSections, language, version, isAdmin);
|
||||
var url = string.Format("{0}{1}?section={2}&allowed={3}&lang={4}&version={5}&admin={6}",
|
||||
baseUrl,
|
||||
_dashboardSettings.Value.ContentDashboardPath,
|
||||
section,
|
||||
allowedSections,
|
||||
language,
|
||||
version,
|
||||
isAdmin);
|
||||
var key = "umbraco-dynamic-dashboard-" + language + allowedSections.Replace(",", "-") + section;
|
||||
|
||||
var content = _appCaches.RuntimeCache.GetCacheItem<JObject>(key);
|
||||
|
||||
@@ -16,9 +16,7 @@ using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
@@ -267,7 +265,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result); //return the id
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -302,12 +300,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (DuplicateNameException ex)
|
||||
{
|
||||
ModelState.AddModelError("Name", ex.Message);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
// map back to display model, and return
|
||||
var display = _umbracoMapper.Map<IDataType, DataTypeDisplay>(dataType.PersistedDataType);
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/dataTypeSaved"), "");
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles", "dataTypeSaved"), "");
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -335,13 +333,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
case MoveOperationStatusType.FailedParentNotFound:
|
||||
return NotFound();
|
||||
case MoveOperationStatusType.FailedCancelledByEvent:
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
case MoveOperationStatusType.FailedNotAllowedByPath:
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy", "notAllowedByPath"), "");
|
||||
return ValidationProblem(notificationModel);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
@@ -355,7 +351,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result);
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,8 +13,6 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
@@ -101,15 +99,15 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
public ActionResult<int> Create(int parentId, string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Key can not be empty."); // TODO: translate
|
||||
return ValidationProblem("Key can not be empty."); // TODO: translate
|
||||
|
||||
if (_localizationService.DictionaryItemExists(key))
|
||||
{
|
||||
var message = _localizedTextService.Localize(
|
||||
"dictionaryItem/changeKeyError",
|
||||
"dictionaryItem","changeKeyError",
|
||||
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings),
|
||||
new Dictionary<string, string> { { "0", key } });
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(message);
|
||||
return ValidationProblem(message);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -130,7 +128,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error creating dictionary with {Name} under {ParentId}", key, parentId);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Error creating dictionary item");
|
||||
return ValidationProblem("Error creating dictionary item");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +205,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
_localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString()));
|
||||
|
||||
if (dictionaryItem == null)
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Dictionary item does not exist");
|
||||
return ValidationProblem("Dictionary item does not exist");
|
||||
|
||||
var userCulture = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings);
|
||||
|
||||
@@ -220,11 +218,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
|
||||
var message = _localizedTextService.Localize(
|
||||
"dictionaryItem/changeKeyError",
|
||||
"dictionaryItem","changeKeyError",
|
||||
userCulture,
|
||||
new Dictionary<string, string> { { "0", dictionary.Name } });
|
||||
ModelState.AddModelError("Name", message);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
dictionaryItem.ItemKey = dictionary.Name;
|
||||
@@ -243,7 +241,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var model = _umbracoMapper.Map<IDictionaryItem, DictionaryDisplay>(dictionaryItem);
|
||||
|
||||
model.Notifications.Add(new BackOfficeNotification(
|
||||
_localizedTextService.Localize("speechBubbles/dictionaryItemSaved", userCulture), string.Empty,
|
||||
_localizedTextService.Localize("speechBubbles","dictionaryItemSaved", userCulture), string.Empty,
|
||||
NotificationStyle.Success));
|
||||
|
||||
return model;
|
||||
@@ -251,7 +249,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error saving dictionary with {Name} under {ParentId}", dictionary.Name, dictionary.ParentId);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Something went wrong saving dictionary");
|
||||
return ValidationProblem("Something went wrong saving dictionary");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||
.Where(x => !x.Name.IsNullOrWhiteSpace())
|
||||
.Select(x => new CultureInfo(x.Name)) // important!
|
||||
.OrderBy(x => x.DisplayName)
|
||||
.ToDictionary(x => x.Name, x => x.DisplayName);
|
||||
.OrderBy(x => x.EnglishName)
|
||||
.ToDictionary(x => x.Name, x => x.EnglishName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,7 +97,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (language.IsDefault)
|
||||
{
|
||||
var message = $"Language '{language.IsoCode}' is currently set to 'default' and can not be deleted.";
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(message);
|
||||
return ValidationProblem(message);
|
||||
}
|
||||
|
||||
// service is happy deleting a language that's fallback for another language,
|
||||
@@ -116,7 +116,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
public ActionResult<Language> SaveLanguage(Language language)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
|
||||
// this is prone to race conditions but the service will not let us proceed anyways
|
||||
var existingByCulture = _localizationService.GetLanguageByIsoCode(language.IsoCode);
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//someone is trying to create a language that already exist
|
||||
ModelState.AddModelError("IsoCode", "The language " + language.IsoCode + " already exists");
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
var existingById = language.Id != default ? _localizationService.GetLanguageById(language.Id) : null;
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (CultureNotFoundException)
|
||||
{
|
||||
ModelState.AddModelError("IsoCode", "No Culture found with name " + language.IsoCode);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
// create it (creating a new language cannot create a fallback cycle)
|
||||
@@ -172,7 +172,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (existingById.IsDefault && !language.IsDefault)
|
||||
{
|
||||
ModelState.AddModelError("IsDefault", "Cannot un-default the default language.");
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
existingById.IsDefault = language.IsDefault;
|
||||
@@ -187,12 +187,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (!languages.ContainsKey(existingById.FallbackLanguageId.Value))
|
||||
{
|
||||
ModelState.AddModelError("FallbackLanguage", "The selected fall back language does not exist.");
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
if (CreatesCycle(existingById, languages))
|
||||
{
|
||||
ModelState.AddModelError("FallbackLanguage", $"The selected fall back language {languages[existingById.FallbackLanguageId.Value].IsoCode} would create a circular path.");
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Logging.Viewer;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
@@ -18,7 +17,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
|
||||
public class LogViewerController : UmbracoAuthorizedJsonController
|
||||
public class LogViewerController : BackOfficeNotificationsController
|
||||
{
|
||||
private readonly ILogViewer _logViewer;
|
||||
|
||||
@@ -51,7 +50,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Unable to view logs, due to size");
|
||||
return ValidationProblem("Unable to view logs, due to size");
|
||||
}
|
||||
|
||||
return _logViewer.GetNumberOfErrors(logTimePeriod);
|
||||
@@ -64,7 +63,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Unable to view logs, due to size");
|
||||
return ValidationProblem("Unable to view logs, due to size");
|
||||
}
|
||||
|
||||
return _logViewer.GetLogLevelCounts(logTimePeriod);
|
||||
@@ -77,7 +76,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Unable to view logs, due to size");
|
||||
return ValidationProblem("Unable to view logs, due to size");
|
||||
}
|
||||
|
||||
return new ActionResult<IEnumerable<LogTemplate>>(_logViewer.GetMessageTemplates(logTimePeriod));
|
||||
@@ -91,7 +90,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//We will need to stop the request if trying to do this on a 1GB file
|
||||
if (CanViewLogs(logTimePeriod) == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Unable to view logs, due to size");
|
||||
return ValidationProblem("Unable to view logs, due to size");
|
||||
}
|
||||
|
||||
var direction = orderDirection == "Descending" ? Direction.Descending : Direction.Ascending;
|
||||
|
||||
@@ -15,7 +15,6 @@ using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
@@ -74,19 +73,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Name can not be empty");
|
||||
return ValidationProblem("Name can not be empty");
|
||||
}
|
||||
|
||||
var alias = name.ToSafeAlias(_shortStringHelper);
|
||||
|
||||
if (_macroService.GetByAlias(alias) != null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Macro with this alias already exists");
|
||||
return ValidationProblem("Macro with this alias already exists");
|
||||
}
|
||||
|
||||
if (name == null || name.Length > 255)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Name cannnot be more than 255 characters in length.");
|
||||
return ValidationProblem("Name cannnot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
try
|
||||
@@ -106,7 +105,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
const string errorMessage = "Error creating macro";
|
||||
_logger.LogError(exception, errorMessage);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(errorMessage);
|
||||
return ValidationProblem(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +116,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {id} does not exist");
|
||||
return ValidationProblem($"Macro with id {id} does not exist");
|
||||
}
|
||||
|
||||
var macroDisplay = MapToDisplay(macro);
|
||||
@@ -132,7 +131,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {id} does not exist");
|
||||
return ValidationProblem($"Macro with id {id} does not exist");
|
||||
}
|
||||
|
||||
var macroDisplay = MapToDisplay(macro);
|
||||
@@ -145,12 +144,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var guidUdi = id as GuidUdi;
|
||||
if (guidUdi == null)
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {id} does not exist");
|
||||
return ValidationProblem($"Macro with id {id} does not exist");
|
||||
|
||||
var macro = _macroService.GetById(guidUdi.Guid);
|
||||
if (macro == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {id} does not exist");
|
||||
return ValidationProblem($"Macro with id {id} does not exist");
|
||||
}
|
||||
|
||||
var macroDisplay = MapToDisplay(macro);
|
||||
@@ -165,7 +164,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {id} does not exist");
|
||||
return ValidationProblem($"Macro with id {id} does not exist");
|
||||
}
|
||||
|
||||
_macroService.Delete(macro);
|
||||
@@ -178,19 +177,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
if (macroDisplay == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("No macro data found in request");
|
||||
return ValidationProblem("No macro data found in request");
|
||||
}
|
||||
|
||||
if (macroDisplay.Name == null || macroDisplay.Name.Length > 255)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Name cannnot be more than 255 characters in length.");
|
||||
return ValidationProblem("Name cannnot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString()));
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult($"Macro with id {macroDisplay.Id} does not exist");
|
||||
return ValidationProblem($"Macro with id {macroDisplay.Id} does not exist");
|
||||
}
|
||||
|
||||
if (macroDisplay.Alias != macro.Alias)
|
||||
@@ -199,7 +198,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (macroByAlias != null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Macro with this alias already exists");
|
||||
return ValidationProblem("Macro with this alias already exists");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +226,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
const string errorMessage = "Error creating macro";
|
||||
_logger.LogError(exception, errorMessage);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(errorMessage);
|
||||
return ValidationProblem(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
Id = Constants.System.RecycleBinMedia,
|
||||
Alias = "recycleBin",
|
||||
ParentId = -1,
|
||||
Name = _localizedTextService.Localize("general/recycleBin"),
|
||||
Name = _localizedTextService.Localize("general", "recycleBin"),
|
||||
ContentTypeAlias = "recycleBin",
|
||||
CreateDate = DateTime.Now,
|
||||
IsContainer = true,
|
||||
@@ -452,9 +452,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
|
||||
if (moveResult == false)
|
||||
{
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -462,9 +460,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var deleteResult = _mediaService.Delete(foundMedia, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
|
||||
if (deleteResult == false)
|
||||
{
|
||||
//returning an object of INotificationModel will ensure that any pending
|
||||
// notification messages are added to the response.
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,11 +496,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (sourceParentID == destinationParentID)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleNotificationModel(new BackOfficeNotification("",_localizedTextService.Localize("media/moveToSameFolderFailed"),NotificationStyle.Error)));
|
||||
return ValidationProblem(new SimpleNotificationModel(new BackOfficeNotification("",_localizedTextService.Localize("media", "moveToSameFolderFailed"),NotificationStyle.Error)));
|
||||
}
|
||||
if (moveResult == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleNotificationModel());
|
||||
return ValidationProblem();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -563,9 +559,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
|
||||
// add the model state to the outgoing object and throw validation response
|
||||
var forDisplay = _umbracoMapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
|
||||
forDisplay.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(forDisplay);
|
||||
MediaItemDisplay forDisplay = _umbracoMapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
|
||||
return ValidationProblem(forDisplay, ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,8 +573,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//lastly, if it is not valid, add the model state to the outgoing object and throw a 403
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
display.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(display, StatusCodes.Status403Forbidden);
|
||||
return ValidationProblem(display, ModelState, StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
//put the correct msgs in
|
||||
@@ -590,8 +584,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (saveStatus.Success)
|
||||
{
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editMediaSaved"),
|
||||
_localizedTextService.Localize("speechBubbles/editMediaSavedText"));
|
||||
_localizedTextService.Localize("speechBubbles", "editMediaSaved"),
|
||||
_localizedTextService.Localize("speechBubbles", "editMediaSavedText"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -602,7 +596,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
// is no Id to redirect to!
|
||||
if (saveStatus.Result.Result == OperationResultType.FailedCancelledByEvent && IsCreatingAction(contentItem.Action))
|
||||
{
|
||||
return new ValidationErrorResult(display);
|
||||
return ValidationProblem(display);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +616,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
_mediaService.EmptyRecycleBin(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty"));
|
||||
return Ok(_localizedTextService.Localize("defaultdialogs", "recycleBinIsEmpty"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -661,7 +655,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (_mediaService.Sort(sortedMedia) == false)
|
||||
{
|
||||
_logger.LogWarning("Media sorting failed, this was probably caused by an event being cancelled");
|
||||
return new ValidationErrorResult("Media sorting failed, this was probably caused by an event being cancelled");
|
||||
return ValidationProblem("Media sorting failed, this was probably caused by an event being cancelled");
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
@@ -837,15 +831,14 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var saveResult = _mediaService.Save(f, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id);
|
||||
if (saveResult == false)
|
||||
{
|
||||
AddCancelMessage(tempFiles,
|
||||
message: _localizedTextService.Localize("speechBubbles/operationCancelledText") + " -- " + mediaItemName);
|
||||
AddCancelMessage(tempFiles, _localizedTextService.Localize("speechBubbles", "operationCancelledText") + " -- " + mediaItemName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempFiles.Notifications.Add(new BackOfficeNotification(
|
||||
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
_localizedTextService.Localize("media/disallowedFileType"),
|
||||
_localizedTextService.Localize("speechBubbles", "operationFailedHeader"),
|
||||
_localizedTextService.Localize("media", "disallowedFileType"),
|
||||
NotificationStyle.Warning));
|
||||
}
|
||||
}
|
||||
@@ -919,7 +912,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ValidationErrorResult("The request was not formatted correctly, the parentId is not an integer, Guid or UDI");
|
||||
return ValidationProblem("The request was not formatted correctly, the parentId is not an integer, Guid or UDI");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,10 +924,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, new MediaPermissionsResource(_mediaService.GetById(intParentId)), requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return new ValidationErrorResult(
|
||||
return ValidationProblem(
|
||||
new SimpleNotificationModel(new BackOfficeNotification(
|
||||
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles/invalidUserPermissionsText"),
|
||||
_localizedTextService.Localize("speechBubbles", "operationFailedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles", "invalidUserPermissionsText"),
|
||||
NotificationStyle.Warning)),
|
||||
StatusCodes.Status403Forbidden);
|
||||
}
|
||||
@@ -969,8 +962,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (toMove.ContentType.AllowedAsRoot == false && mediaTypeService.GetAll().Any(ct => ct.AllowedAsRoot))
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedAtRoot"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy", "notAllowedAtRoot"), "");
|
||||
return ValidationProblem(notificationModel);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -987,16 +980,16 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
.Any(x => x.Value == toMove.ContentType.Id) == false)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedByContentType"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy", "notAllowedByContentType"), "");
|
||||
return ValidationProblem(notificationModel);
|
||||
}
|
||||
|
||||
// Check on paths
|
||||
if ((string.Format(",{0},", parent.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedByPath"), "");
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy", "notAllowedByPath"), "");
|
||||
return ValidationProblem(notificationModel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result); //return the id
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessMediaTypes)]
|
||||
@@ -277,7 +277,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (result.Success)
|
||||
return Ok(result.Result); //return the id
|
||||
else
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
|
||||
return ValidationProblem(result.Exception.Message);
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessMediaTypes)]
|
||||
@@ -297,7 +297,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/mediaTypeSavedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles","mediaTypeSavedHeader"),
|
||||
string.Empty);
|
||||
|
||||
return display;
|
||||
|
||||
@@ -26,11 +26,8 @@ using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.BackOffice.ModelBinders;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
@@ -260,8 +257,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
MemberDisplay forDisplay = _umbracoMapper.Map<MemberDisplay>(contentItem.PersistedContent);
|
||||
forDisplay.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(forDisplay);
|
||||
return ValidationProblem(forDisplay, ModelState);
|
||||
}
|
||||
|
||||
// Create a scope here which will wrap all child data operations in a single transaction.
|
||||
@@ -300,8 +296,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
// lastly, if it is not valid, add the model state to the outgoing object and throw a 403
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
display.Errors = ModelState.ToErrorDictionary();
|
||||
return new ValidationErrorResult(display, StatusCodes.Status403Forbidden);
|
||||
return ValidationProblem(display, ModelState, StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
// put the correct messages in
|
||||
@@ -310,8 +305,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
case ContentSaveAction.Save:
|
||||
case ContentSaveAction.SaveNew:
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/editMemberSaved"),
|
||||
_localizedTextService.Localize("speechBubbles/editMemberSaved"));
|
||||
_localizedTextService.Localize("speechBubbles","editMemberSaved"),
|
||||
_localizedTextService.Localize("speechBubbles","editMemberSaved"));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -373,7 +368,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (created.Succeeded == false)
|
||||
{
|
||||
return new ValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
return ValidationProblem(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
// now re-look up the member, which will now exist
|
||||
@@ -460,7 +455,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
MemberIdentityUser identityMember = await _memberManager.FindByIdAsync(contentItem.Id.ToString());
|
||||
if (identityMember == null)
|
||||
{
|
||||
return new ValidationErrorResult("Member was not found");
|
||||
return ValidationProblem("Member was not found");
|
||||
}
|
||||
|
||||
// Handle unlocking with the member manager (takes care of other nuances)
|
||||
@@ -469,7 +464,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
IdentityResult unlockResult = await _memberManager.SetLockoutEndDateAsync(identityMember, DateTimeOffset.Now.AddMinutes(-1));
|
||||
if (unlockResult.Succeeded == false)
|
||||
{
|
||||
return new ValidationErrorResult(
|
||||
return ValidationProblem(
|
||||
$"Could not unlock for member {contentItem.Id} - error {unlockResult.Errors.ToErrorMessage()}");
|
||||
}
|
||||
needsResync = true;
|
||||
@@ -478,7 +473,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
// NOTE: This should not ever happen unless someone is mucking around with the request data.
|
||||
// An admin cannot simply lock a user, they get locked out by password attempts, but an admin can unlock them
|
||||
return new ValidationErrorResult("An admin cannot lock a member");
|
||||
return ValidationProblem("An admin cannot lock a member");
|
||||
}
|
||||
|
||||
// If we're changing the password...
|
||||
@@ -488,13 +483,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
IdentityResult validatePassword = await _memberManager.ValidatePasswordAsync(contentItem.Password.NewPassword);
|
||||
if (validatePassword.Succeeded == false)
|
||||
{
|
||||
return new ValidationErrorResult(validatePassword.Errors.ToErrorMessage());
|
||||
return ValidationProblem(validatePassword.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
Attempt<int> intId = identityMember.Id.TryConvertTo<int>();
|
||||
if (intId.Success == false)
|
||||
{
|
||||
return new ValidationErrorResult("Member ID was not valid");
|
||||
return ValidationProblem("Member ID was not valid");
|
||||
}
|
||||
|
||||
var changingPasswordModel = new ChangingPasswordModel
|
||||
@@ -513,7 +508,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError?.ErrorMessage ?? string.Empty);
|
||||
}
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
needsResync = true;
|
||||
@@ -622,7 +617,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
IdentityResult identityResult = await _memberManager.RemoveFromRolesAsync(identityMember, rolesToRemove);
|
||||
if (!identityResult.Succeeded)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(identityResult.Errors.ToErrorMessage());
|
||||
return ValidationProblem(identityResult.Errors.ToErrorMessage());
|
||||
}
|
||||
hasChanges = true;
|
||||
}
|
||||
@@ -635,7 +630,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
IdentityResult identityResult = await _memberManager.AddToRolesAsync(identityMember, toAdd);
|
||||
if (!identityResult.Succeeded)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(identityResult.Errors.ToErrorMessage());
|
||||
return ValidationProblem(identityResult.Errors.ToErrorMessage());
|
||||
}
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
MemberGroupDisplay display = _umbracoMapper.Map<IMemberGroup, MemberGroupDisplay>(memberGroup);
|
||||
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/memberGroupSavedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles","memberGroupSavedHeader"),
|
||||
string.Empty);
|
||||
|
||||
return display;
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var display =_umbracoMapper.Map<MemberTypeDisplay>(savedCt.Value);
|
||||
|
||||
display.AddSuccessNotification(
|
||||
_localizedTextService.Localize("speechBubbles/memberTypeSavedHeader"),
|
||||
_localizedTextService.Localize("speechBubbles","memberTypeSavedHeader"),
|
||||
string.Empty);
|
||||
|
||||
return display;
|
||||
|
||||
@@ -88,14 +88,16 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
public ActionResult<PackageDefinition> PostSavePackage(PackageDefinition model)
|
||||
{
|
||||
if (ModelState.IsValid == false)
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
|
||||
//save it
|
||||
if (!_packagingService.SaveCreatedPackage(model))
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(
|
||||
{
|
||||
return ValidationProblem(
|
||||
model.Id == default
|
||||
? $"A package with the name {model.Name} already exists"
|
||||
: $"The package with id {model.Id} was not found");
|
||||
}
|
||||
|
||||
_packagingService.ExportCreatedPackage(model);
|
||||
|
||||
@@ -153,7 +155,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return NotFound();
|
||||
|
||||
if (!System.IO.File.Exists(package.PackagePath))
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("No file found for path " + package.PackagePath);
|
||||
return ValidationProblem("No file found for path " + package.PackagePath);
|
||||
|
||||
var fileName = Path.GetFileName(package.PackagePath);
|
||||
|
||||
@@ -161,7 +163,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = WebUtility.UrlEncode(fileName),
|
||||
FileName = WebUtility.UrlEncode(fileName),
|
||||
Inline = false // false = prompt the user for downloading; true = browser to try to show the file inline
|
||||
};
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error creating relation type with {Name}", relationType.Name);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Error creating relation type.");
|
||||
return ValidationProblem("Error creating relation type.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (relationTypePersisted == null)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Relation type does not exist");
|
||||
return ValidationProblem("Relation type does not exist");
|
||||
}
|
||||
|
||||
_umbracoMapper.Map(relationType, relationTypePersisted);
|
||||
@@ -185,7 +185,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error saving relation type with {Id}", relationType.Id);
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Something went wrong when saving the relation type");
|
||||
return ValidationProblem("Something went wrong when saving the relation type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,28 +47,28 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
private IEnumerable<OperatorTerm> Terms => new List<OperatorTerm>
|
||||
{
|
||||
new OperatorTerm(_localizedTextService.Localize("template/is"), Operator.Equals, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/isNot"), Operator.NotEquals, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/before"), Operator.LessThan, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/beforeIncDate"), Operator.LessThanEqualTo, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/after"), Operator.GreaterThan, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/afterIncDate"), Operator.GreaterThanEqualTo, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/equals"), Operator.Equals, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/doesNotEqual"), Operator.NotEquals, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/contains"), Operator.Contains, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/doesNotContain"), Operator.NotContains, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/greaterThan"), Operator.GreaterThan, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/greaterThanEqual"), Operator.GreaterThanEqualTo, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/lessThan"), Operator.LessThan, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template/lessThanEqual"), Operator.LessThanEqualTo, new [] {"int"})
|
||||
new OperatorTerm(_localizedTextService.Localize("template","is"), Operator.Equals, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","isNot"), Operator.NotEquals, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","before"), Operator.LessThan, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","beforeIncDate"), Operator.LessThanEqualTo, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","after"), Operator.GreaterThan, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","afterIncDate"), Operator.GreaterThanEqualTo, new [] {"datetime"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","equals"), Operator.Equals, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","doesNotEqual"), Operator.NotEquals, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","contains"), Operator.Contains, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","doesNotContain"), Operator.NotContains, new [] {"string"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","greaterThan"), Operator.GreaterThan, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","greaterThanEqual"), Operator.GreaterThanEqualTo, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","lessThan"), Operator.LessThan, new [] {"int"}),
|
||||
new OperatorTerm(_localizedTextService.Localize("template","lessThanEqual"), Operator.LessThanEqualTo, new [] {"int"})
|
||||
};
|
||||
|
||||
private IEnumerable<PropertyModel> Properties => new List<PropertyModel>
|
||||
{
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template/id"), Alias = "Id", Type = "int" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template/name"), Alias = "Name", Type = "string" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template/createdDate"), Alias = "CreateDate", Type = "datetime" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template/lastUpdatedDate"), Alias = "UpdateDate", Type = "datetime" }
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template","id"), Alias = "Id", Type = "int" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template","name"), Alias = "Name", Type = "string" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template","createdDate"), Alias = "CreateDate", Type = "datetime" },
|
||||
new PropertyModel { Name = _localizedTextService.Localize("template","lastUpdatedDate"), Alias = "UpdateDate", Type = "datetime" }
|
||||
};
|
||||
|
||||
public QueryResultModel PostTemplateQuery(QueryModel model)
|
||||
@@ -232,10 +232,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
public IEnumerable<ContentTypeModel> GetContentTypes()
|
||||
{
|
||||
var contentTypes = _contentTypeService.GetAll()
|
||||
.Select(x => new ContentTypeModel { Alias = x.Alias, Name = _localizedTextService.Localize("template/contentOfType", tokens: new string[] { x.Name }) })
|
||||
.Select(x => new ContentTypeModel { Alias = x.Alias, Name = _localizedTextService.Localize("template", "contentOfType", tokens: new string[] { x.Name }) })
|
||||
.OrderBy(x => x.Name).ToList();
|
||||
|
||||
contentTypes.Insert(0, new ContentTypeModel { Alias = string.Empty, Name = _localizedTextService.Localize("template/allContent") });
|
||||
contentTypes.Insert(0, new ContentTypeModel { Alias = string.Empty, Name = _localizedTextService.Localize("template", "allContent") });
|
||||
|
||||
return contentTypes;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -25,6 +32,91 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[MiddlewareFilter(typeof(UnhandledExceptionLoggerFilter))]
|
||||
public abstract class UmbracoAuthorizedApiController : UmbracoApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a validation problem result for the <see cref="IErrorModel"/> and the <see cref="ModelStateDictionary"/>
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="modelStateDictionary"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ActionResult ValidationProblem(IErrorModel model, ModelStateDictionary modelStateDictionary, int statusCode = StatusCodes.Status400BadRequest)
|
||||
{
|
||||
model.Errors = modelStateDictionary.ToErrorDictionary();
|
||||
return ValidationProblem(model, statusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to return Umbraco compatible errors
|
||||
/// </summary>
|
||||
/// <param name="modelStateDictionary"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public override ActionResult ValidationProblem(ModelStateDictionary modelStateDictionary)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(modelStateDictionary.ToErrorDictionary()));
|
||||
|
||||
//ValidationProblemDetails problemDetails = GetValidationProblemDetails(modelStateDictionary: modelStateDictionary);
|
||||
//return new ValidationErrorResult(problemDetails);
|
||||
}
|
||||
|
||||
// creates validation problem details instance.
|
||||
// borrowed from netcore: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1970
|
||||
protected ValidationProblemDetails GetValidationProblemDetails(
|
||||
string detail = null,
|
||||
string instance = null,
|
||||
int? statusCode = null,
|
||||
string title = null,
|
||||
string type = null,
|
||||
[ActionResultObjectValue] ModelStateDictionary modelStateDictionary = null)
|
||||
{
|
||||
modelStateDictionary ??= ModelState;
|
||||
|
||||
ValidationProblemDetails validationProblem;
|
||||
if (ProblemDetailsFactory == null)
|
||||
{
|
||||
// ProblemDetailsFactory may be null in unit testing scenarios. Improvise to make this more testable.
|
||||
validationProblem = new ValidationProblemDetails(modelStateDictionary)
|
||||
{
|
||||
Detail = detail,
|
||||
Instance = instance,
|
||||
Status = statusCode,
|
||||
Title = title,
|
||||
Type = type,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
validationProblem = ProblemDetailsFactory?.CreateValidationProblemDetails(
|
||||
HttpContext,
|
||||
modelStateDictionary,
|
||||
statusCode: statusCode,
|
||||
title: title,
|
||||
type: type,
|
||||
detail: detail,
|
||||
instance: instance);
|
||||
}
|
||||
|
||||
return validationProblem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an Umbraco compatible validation problem for the given error message
|
||||
/// </summary>
|
||||
/// <param name="errorMessage"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ActionResult ValidationProblem(string errorMessage)
|
||||
{
|
||||
ValidationProblemDetails problemDetails = GetValidationProblemDetails(errorMessage);
|
||||
return new ValidationErrorResult(problemDetails);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an Umbraco compatible validation problem for the object result
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ActionResult ValidationProblem(object value, int statusCode = StatusCodes.Status400BadRequest)
|
||||
=> new ValidationErrorResult(value, statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.BackOffice.ActionResults;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
@@ -22,7 +21,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
|
||||
[PrefixlessBodyModelValidator]
|
||||
public class UserGroupsController : UmbracoAuthorizedJsonController
|
||||
public class UserGroupsController : BackOfficeNotificationsController
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentService _contentService;
|
||||
@@ -118,7 +117,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
var display = _umbracoMapper.Map<UserGroupDisplay>(userGroupSave.PersistedUserGroup);
|
||||
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/operationSavedHeader"), _localizedTextService.Localize("speechBubbles/editUserGroupSaved"));
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles","operationSavedHeader"), _localizedTextService.Localize("speechBubbles","editUserGroupSaved"));
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -202,10 +201,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
_userService.DeleteUserGroup(userGroup);
|
||||
}
|
||||
if (userGroups.Length > 1)
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/deleteUserGroupsSuccess", new[] {userGroups.Length.ToString()}));
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/deleteUserGroupSuccess", new[] {userGroups[0].Name}));
|
||||
{
|
||||
return Ok(_localizedTextService.Localize("speechBubbles","deleteUserGroupsSuccess", new[] {userGroups.Length.ToString()}));
|
||||
}
|
||||
|
||||
return Ok(_localizedTextService.Localize("speechBubbles","deleteUserGroupSuccess", new[] {userGroups[0].Name}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
|
||||
[PrefixlessBodyModelValidator]
|
||||
[IsCurrentUserModelFilter]
|
||||
public class UsersController : UmbracoAuthorizedJsonController
|
||||
public class UsersController : BackOfficeNotificationsController
|
||||
{
|
||||
private readonly MediaFileManager _mediaFileManager;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
@@ -128,7 +128,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
var urls = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator);
|
||||
if (urls == null)
|
||||
return new ValidationErrorResult("Could not access Gravatar endpoint");
|
||||
return ValidationProblem("Could not access Gravatar endpoint");
|
||||
|
||||
return urls;
|
||||
}
|
||||
@@ -345,7 +345,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
if (_securitySettings.UsernameIsEmail)
|
||||
@@ -362,7 +362,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
//Perform authorization here to see if the current user can actually save this user with the info being requested
|
||||
@@ -380,7 +380,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var created = await _userManager.CreateAsync(identityUser);
|
||||
if (created.Succeeded == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
return ValidationProblem(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
string resetPassword;
|
||||
@@ -389,7 +389,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var result = await _userManager.AddPasswordAsync(identityUser, password);
|
||||
if (result.Succeeded == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
return ValidationProblem(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
resetPassword = password;
|
||||
@@ -446,19 +446,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
if (!_emailSender.CanSendRequiredEmail())
|
||||
{
|
||||
return new ValidationErrorResult("No Email server is configured");
|
||||
return ValidationProblem("No Email server is configured");
|
||||
}
|
||||
|
||||
//Perform authorization here to see if the current user can actually save this user with the info being requested
|
||||
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, user, null, null, userSave.UserGroups);
|
||||
if (canSaveUser == false)
|
||||
{
|
||||
return new ValidationErrorResult(canSaveUser.Result, StatusCodes.Status401Unauthorized);
|
||||
return ValidationProblem(canSaveUser.Result, StatusCodes.Status401Unauthorized);
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
@@ -471,7 +471,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var created = await _userManager.CreateAsync(identityUser);
|
||||
if (created.Succeeded == false)
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
return ValidationProblem(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
//now re-look the user back up
|
||||
@@ -491,7 +491,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
//send the email
|
||||
await SendUserInviteEmailAsync(display, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Name, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Email, user, userSave.Message);
|
||||
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/resendInviteHeader"), _localizedTextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name }));
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles","resendInviteHeader"), _localizedTextService.Localize("speechBubbles","resendInviteSuccess", new[] { user.Name }));
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
ModelState.AddModelError(
|
||||
_securitySettings.UsernameIsEmail ? "Email" : "Username",
|
||||
"A user with the username already exists");
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
return new ActionResult<IUser>(user);
|
||||
@@ -543,10 +543,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var applicationUri = _hostingEnvironment.ApplicationMainUrl;
|
||||
var inviteUri = new Uri(applicationUri, action);
|
||||
|
||||
var emailSubject = _localizedTextService.Localize("user/inviteEmailCopySubject",
|
||||
var emailSubject = _localizedTextService.Localize("user","inviteEmailCopySubject",
|
||||
//Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(to.Language, _localizedTextService, _globalSettings));
|
||||
var emailBody = _localizedTextService.Localize("user/inviteEmailCopyFormat",
|
||||
var emailBody = _localizedTextService.Localize("user","inviteEmailCopyFormat",
|
||||
//Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(to.Language, _localizedTextService, _globalSettings),
|
||||
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
|
||||
@@ -568,7 +568,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
var intId = userSave.Id.TryConvertTo<int>();
|
||||
@@ -631,7 +631,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
if (hasErrors)
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
|
||||
//merge the save data onto the user
|
||||
var user = _umbracoMapper.Map(userSave, found);
|
||||
@@ -645,11 +645,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var userHasChangedOwnLanguage =
|
||||
user.Id == currentUser.Id && currentUser.Language != user.Language;
|
||||
|
||||
var textToLocalise = userHasChangedOwnLanguage ? "speechBubbles/operationSavedHeaderReloadUser" : "speechBubbles/operationSavedHeader";
|
||||
var textToLocalise = userHasChangedOwnLanguage ? "operationSavedHeaderReloadUser" : "operationSavedHeader";
|
||||
var culture = userHasChangedOwnLanguage
|
||||
? CultureInfo.GetCultureInfo(user.Language)
|
||||
: Thread.CurrentThread.CurrentUICulture;
|
||||
display.AddSuccessNotification(_localizedTextService.Localize(textToLocalise, culture), _localizedTextService.Localize("speechBubbles/editUserSaved", culture));
|
||||
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles", textToLocalise, culture), _localizedTextService.Localize("speechBubbles","editUserSaved", culture));
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
Attempt<int> intId = changingPasswordModel.Id.TryConvertTo<int>();
|
||||
@@ -684,12 +684,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
// if it's the current user, the current user cannot reset their own password without providing their old password
|
||||
if (currentUser.Username == found.Username && string.IsNullOrEmpty(changingPasswordModel.OldPassword))
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("Password reset is not allowed without providing old password");
|
||||
return ValidationProblem("Password reset is not allowed without providing old password");
|
||||
}
|
||||
|
||||
if (!currentUser.IsAdmin() && found.IsAdmin())
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot change the password for the specified user");
|
||||
return ValidationProblem("The current user cannot change the password for the specified user");
|
||||
}
|
||||
|
||||
Attempt<PasswordChangedModel> passwordChangeResult = await _passwordChanger.ChangePasswordWithIdentityAsync(changingPasswordModel, _userManager);
|
||||
@@ -697,7 +697,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
if (passwordChangeResult.Success)
|
||||
{
|
||||
var result = new ModelWithNotifications<string>(passwordChangeResult.Result.ResetPassword);
|
||||
result.AddSuccessNotification(_localizedTextService.Localize("general/success"), _localizedTextService.Localize("user/passwordChangedGeneric"));
|
||||
result.AddSuccessNotification(_localizedTextService.Localize("general","success"), _localizedTextService.Localize("user","passwordChangedGeneric"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -706,7 +706,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError.ErrorMessage);
|
||||
}
|
||||
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
|
||||
|
||||
@@ -720,7 +720,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var tryGetCurrentUserId = _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId();
|
||||
if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result))
|
||||
{
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot disable itself");
|
||||
return ValidationProblem("The current user cannot disable itself");
|
||||
}
|
||||
|
||||
var users = _userService.GetUsersById(userIds).ToArray();
|
||||
@@ -733,12 +733,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (users.Length > 1)
|
||||
{
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/disableUsersSuccess", new[] {userIds.Length.ToString()}));
|
||||
return Ok(_localizedTextService.Localize("speechBubbles","disableUsersSuccess", new[] {userIds.Length.ToString()}));
|
||||
}
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/disableUserSuccess", new[] { users[0].Name }));
|
||||
return Ok(_localizedTextService.Localize("speechBubbles","disableUserSuccess", new[] { users[0].Name }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -757,12 +755,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
if (users.Length > 1)
|
||||
{
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/enableUsersSuccess", new[] { userIds.Length.ToString() }));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","enableUsersSuccess", new[] { userIds.Length.ToString() }));
|
||||
}
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/enableUserSuccess", new[] { users[0].Name }));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","enableUserSuccess", new[] { users[0].Name }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -787,19 +785,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var unlockResult = await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now.AddMinutes(-1));
|
||||
if (unlockResult.Succeeded == false)
|
||||
{
|
||||
return new ValidationErrorResult(
|
||||
return ValidationProblem(
|
||||
$"Could not unlock for user {u} - error {unlockResult.Errors.ToErrorMessage()}");
|
||||
}
|
||||
|
||||
if (userIds.Length == 1)
|
||||
{
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/unlockUserSuccess", new[] {user.Name}));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","unlockUserSuccess", new[] {user.Name}));
|
||||
}
|
||||
}
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/unlockUsersSuccess", new[] {(userIds.Length - notFound.Count).ToString()}));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","unlockUsersSuccess", new[] {(userIds.Length - notFound.Count).ToString()}));
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
|
||||
@@ -816,8 +814,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
}
|
||||
}
|
||||
_userService.Save(users);
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/setUserGroupOnUsersSuccess"));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","setUserGroupOnUsersSuccess"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -847,8 +845,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
var userName = user.Name;
|
||||
_userService.Delete(user, true);
|
||||
|
||||
return new UmbracoNotificationSuccessResponse(
|
||||
_localizedTextService.Localize("speechBubbles/deleteUserSuccess", new[] { userName }));
|
||||
return Ok(
|
||||
_localizedTextService.Localize("speechBubbles","deleteUserSuccess", new[] { userName }));
|
||||
}
|
||||
|
||||
public class PagedUserResult : PagedResult<UserBasic>
|
||||
|
||||
@@ -6,18 +6,11 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Umbraco.Cms.Web.BackOffice.PropertyEditors.Validation;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Extensions
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class ModelStateExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if there are any model errors on any fields containing the prefix
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="prefix"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValid(this ModelStateDictionary state, string prefix) =>
|
||||
state.Where(v => v.Key.StartsWith(prefix + ".")).All(v => !v.Value.Errors.Any());
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="ValidationResult"/> to the model state with the appropriate keys for property errors
|
||||
@@ -171,42 +164,5 @@ namespace Umbraco.Cms.Web.BackOffice.Extensions
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static IDictionary<string, object> ToErrorDictionary(this ModelStateDictionary modelState)
|
||||
{
|
||||
var modelStateError = new Dictionary<string, object>();
|
||||
foreach (KeyValuePair<string, ModelStateEntry> keyModelStatePair in modelState)
|
||||
{
|
||||
var key = keyModelStatePair.Key;
|
||||
ModelErrorCollection errors = keyModelStatePair.Value.Errors;
|
||||
if (errors != null && errors.Count > 0)
|
||||
{
|
||||
modelStateError.Add(key, errors.Select(error => error.ErrorMessage));
|
||||
}
|
||||
}
|
||||
return modelStateError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the ModelState to JSON for JavaScript to interrogate the errors
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonResult ToJsonErrors(this ModelStateDictionary state) =>
|
||||
new JsonResult(new
|
||||
{
|
||||
success = state.IsValid.ToString().ToLower(),
|
||||
failureType = "ValidationError",
|
||||
validationErrors = from e in state
|
||||
where e.Value.Errors.Count > 0
|
||||
select new
|
||||
{
|
||||
name = e.Key,
|
||||
errors = e.Value.Errors.Select(x => x.ErrorMessage)
|
||||
.Concat(
|
||||
e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user