Merge remote-tracking branch 'origin/contrib' into v15/dev

This commit is contained in:
Jacob Overgaard
2024-11-09 11:23:45 +01:00
9 changed files with 124 additions and 28 deletions

View File

@@ -1,4 +1,4 @@
using Umbraco.Cms.Api.Management.Mapping.ContentType;
using Umbraco.Cms.Api.Management.Mapping.ContentType;
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
using Umbraco.Cms.Core.Mapping;
@@ -39,6 +39,7 @@ public class DocumentTypeMapDefinition : ContentTypeMapDefinition<IContentType,
target.Properties = MapPropertyTypes(source);
target.AllowedDocumentTypes = source.AllowedContentTypes?.Select(ct =>
new DocumentTypeSort { DocumentType = new ReferenceByIdModel(ct.Key), SortOrder = ct.SortOrder })
.OrderBy(ct => ct.SortOrder)
.ToArray() ?? Enumerable.Empty<DocumentTypeSort>();
target.Compositions = MapNestedCompositions(
source.ContentTypeComposition,

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<language alias="cy_gb" intName="Welsh (UK)" localName="Cymraeg (UK)" lcid="1106" culture="cy-GB">
<creator>
<name>Method4 Ltd</name>
@@ -82,7 +82,8 @@
<area alias="login">
<key alias="resetCodeExpired">Mae'r ddolen rydych wedi clicio arno naill ai yn annilys neu wedi dod i ben</key>
<key alias="resetPasswordEmailCopySubject">Umbraco: Ailosod Cyfrinair</key>
<key alias="resetPasswordEmailCopyFormat"><![CDATA[
<key alias="resetPasswordEmailCopyFormat">
<![CDATA[
<html>
<head>
<meta name='viewport' content='width=device-width'>
@@ -162,10 +163,12 @@
</table>
</body>
</html>
]]></key>
]]>
</key>
</area>
<area alias="notifications">
<key alias="mailBody"><![CDATA[
<key alias="mailBody">
<![CDATA[
Helo %0%
Mae hyn yn ebost awtomatig i'ch hysbysu fod y dasg '%1%'
@@ -177,9 +180,11 @@
Mwynhewch eich diwrnod!
Hwyl fawr oddi wrth y robot Umbraco
]]></key>
]]>
</key>
<key alias="mailBodyVariantSummary">Mae'r ieithoedd canlynol wedi'u haddasu %0%</key>
<key alias="mailBodyHtml"><![CDATA[
<key alias="mailBodyHtml">
<![CDATA[
<html>
<head>
<meta name='viewport' content='width=device-width'>
@@ -256,16 +261,20 @@
</table>
</body>
</html>
]]></key>
<key alias="mailBodyVariantHtmlSummary"><![CDATA[<p>Mae'r ieithoedd canlynol wedi'u haddasu:</p>
]]>
</key>
<key alias="mailBodyVariantHtmlSummary">
<![CDATA[<p>Mae'r ieithoedd canlynol wedi'u haddasu:</p>
%0%
]]></key>
]]>
</key>
<key alias="mailSubject">[%0%] Hysbysiad am %1% wedi perfformio am %2%</key>
</area>
<area alias="user">
<key alias="passwordMismatch">Nid yw'r cyfrinair cadarnhau yn cyfateb â'r cyfrinair newydd!</key>
<key alias="inviteEmailCopySubject">Umbraco: Gwahoddiad</key>
<key alias="inviteEmailCopyFormat"><![CDATA[
<key alias="inviteEmailCopyFormat">
<![CDATA[
<html>
<head>
<meta name='viewport' content='width=device-width'>
@@ -355,7 +364,8 @@
</tr>
</table>
</body>
</html>]]></key>
</html>]]>
</key>
<key alias="duplicateLogin">Mae defnyddiwr gyda'r mewngofnodi hwn eisoes yn bodoli</key>
<key alias="passwordRequiresDigit">Rhaid bod gan y cyfrinair o leiaf un digid ('0'-'9')</key>
<key alias="passwordRequiresLower">Rhaid bod gan y cyfrinair o leiaf un llythrennau bach ('a'-'z')</key>
@@ -414,6 +424,8 @@
<!-- The following keys don't get tokens passed in -->
<key alias="compilationDebugCheckSuccessMessage">Modd casgliad dadfygio wedi'i analluogi.</key>
<key alias="compilationDebugCheckErrorMessage">Modd casgliad dadfygio wedi'i alluogi. Argymhellwyd analluogi'r gosodiad yma cyn mynd yn fyw.</key>
<key alias="runtimeModeCheckSuccessMessage">Mae'r modd rhedeg wedi'i osod i gynhyrchu.</key>
<key alias="runtimeModeCheckErrorMessage">Nid yw'r modd rhedeg wedi'i osod i Gynhyrchu. Argymhellir gosod y Modd Rhedeg i Gynhyrchu ar gyfer amgylcheddau byw/cynhyrchu.</key>
<!-- The following keys get these tokens passed in:
0: Comma delimitted list of failed folder paths
-->
@@ -426,14 +438,12 @@
<key alias="noSniffCheckHeaderNotFound"><![CDATA[Nid yw'r peniad neu meta-tag <strong>X-Content-Type-Options</strong> sy'n cael ei ddefnyddio i amddiffyn yn erbyn gwendidau sniffio MIME wedi'i ganfod.]]></key>
<key alias="hSTSCheckHeaderFound"><![CDATA[Mae'r peniad <strong>Strict-Transport-Security</strong>, hefyd wedi'i adnabod fel HSTS-header, wedi'i ganfod.]]></key>
<key alias="hSTSCheckHeaderNotFound"><![CDATA[Nid yw'r peniad <strong>Strict-Transport-Security</strong> wedi'i ganfod.]]></key>
<key alias="hSTSCheckHeaderFoundOnLocalhost">
<![CDATA[Darganfuwyd y pennyn <strong>Strict-Transport-Security</strong>, a elwir hefyd yn HSTS-header. <strong>Ni ddylai'r pennyn hwn fod yn bresennol ar localhost.</strong>]]>
</key>
<key alias="hSTSCheckHeaderNotFoundOnLocalhost">
<![CDATA[Ni ddaethpwyd o hyd i'r pennyn <strong>Strict-Transport-Security</strong>. Ni ddylai'r pennyn hwn fod yn bresennol ar localhost.]]>
</key>
<key alias="hSTSCheckHeaderFoundOnLocalhost"><![CDATA[Darganfuwyd y pennyn <strong>Strict-Transport-Security</strong>, a elwir hefyd yn HSTS-header. <strong>Ni ddylai'r pennyn hwn fod yn bresennol ar localhost.</strong>]]></key>
<key alias="hSTSCheckHeaderNotFoundOnLocalhost"><![CDATA[Ni ddaethpwyd o hyd i'r pennyn <strong>Strict-Transport-Security</strong>. Ni ddylai'r pennyn hwn fod yn bresennol ar localhost.]]></key>
<key alias="xssProtectionCheckHeaderFound"><![CDATA[Mae'r peniad <strong>X-XSS-Protection</strong> wedi'i ganfod.]]></key>
<key alias="xssProtectionCheckHeaderNotFound"><![CDATA[Nid yw'r peniad <strong>X-XSS-Protection</strong> wedi'i ganfod.]]></key>
<key alias="contentSecurityPolicyCheckHeaderFound"><![CDATA[Mae'r peniad <strong>Content-Security-Policy (CSP)</strong> wedi'i ganfod.]]></key>
<key alias="contentSecurityPolicyCheckHeaderNotFound"><![CDATA[Nid yw'r peniad <strong>Content-Security-Policy (CSP)</strong>, a ddefnyddir i atal ymosodiadau sgriptio traws-safle (XSS) a gwendidau pigiad cod eraill, wedi'i ganfod.]]></key>
<key alias="excessiveHeadersFound"><![CDATA[Mae'r peniadau canlynol sy'n datgelu gwynodaeth am dechnoleg eich gwefan wedi'u canfod: <strong>%0%</strong>.]]></key>
<key alias="excessiveHeadersNotFound">Dim peniadau sy'n datgelu gwynodaeth am dechnoleg eich gwefan wedi'u canfod.</key>
<key alias="smtpMailSettingsConnectionSuccess">Gosodiadau SMTP wedi ffurfweddu'n gywir ac mae'r gwasanaeth yn gweithio fel y disgwylir.</key>
@@ -463,8 +473,17 @@
<key alias="minimalLevelDescription">Byddwn ond yn anfon ID safle dienw i roi gwybod i ni bod y wefan yn bodoli.</key>
<key alias="basicLevelDescription">Byddwn yn anfon ID safle dienw, fersiwn Umbraco, a phecynnau wedi'u gosod</key>
<key alias="detailedLevelDescription">
Byddwn yn anfon:
<ul><li>ID safle dienw, fersiwn Umbraco, a phecynnau wedi'u gosod.</li><li>Nifer o: Nodau gwraidd, Nodau Cynnwys, Macros, Cyfryngau, Mathau o Ddogfen, Templedi, Ieithoedd, Parthau, Grŵp Defnyddwyr, Defnyddwyr, Aelodau, a Golygyddion Eiddo a ddefnyddir.</li><li>Gwybodaeth system: Webserver, gweinydd OS, fframwaith gweinydd, iaith gweinyddwr OS, a darparwr cronfa ddata.</li><li>Gosodiadau cyfluniad: Modd Modelsbuilder, os oes llwybr Umbraco arferol yn bodoli, amgylchedd ASP, ac os ydych chi yn y modd dadfygio.</li></ul><em>Efallai y byddwn yn newid yr hyn a anfonwn ar y lefel Fanwl yn y dyfodol. Os felly, fe'i rhestrir uchod.
<br />Drwy ddewis "Manwl" rydych yn cytuno i wybodaeth ddienw yn awr ac yn y dyfodol gael ei chasglu.</em></key>
Byddwn yn anfon:
<ul>
<li>ID safle dienw, fersiwn Umbraco, a phecynnau wedi'u gosod.</li>
<li>Nifer o: Nodau gwraidd, Nodau Cynnwys, Macros, Cyfryngau, Mathau o Ddogfen, Templedi, Ieithoedd, Parthau, Grŵp Defnyddwyr, Defnyddwyr, Aelodau, a Golygyddion Eiddo a ddefnyddir.</li>
<li>Gwybodaeth system: Webserver, gweinydd OS, fframwaith gweinydd, iaith gweinyddwr OS, a darparwr cronfa ddata.</li>
<li>Gosodiadau cyfluniad: Modd Modelsbuilder, os oes llwybr Umbraco arferol yn bodoli, amgylchedd ASP, ac os ydych chi yn y modd dadfygio.</li>
</ul>
<em>
Efallai y byddwn yn newid yr hyn a anfonwn ar y lefel Fanwl yn y dyfodol. Os felly, fe'i rhestrir uchod.
<br />Drwy ddewis "Manwl" rydych yn cytuno i wybodaeth ddienw yn awr ac yn y dyfodol gael ei chasglu.
</em>
</key>
</area>
</language>

View File

@@ -14,7 +14,7 @@ public class YouTube : OEmbedProviderBase
public override string ApiEndpoint => "https://www.youtube.com/oembed";
public override string[] UrlSchemeRegex => new[] { @"youtu.be/.*", @"youtube.com/watch.*", @"youtube.com/shorts/.*" };
public override string[] UrlSchemeRegex => new[] { @"youtu.be/.*", @"youtube.com/watch.*", @"youtube.com/shorts/.*", @"youtube.com/live/.*" };
public override Dictionary<string, string> RequestParams => new()
{

View File

@@ -100,7 +100,7 @@ public interface IPublishedContent : IPublishedElement
/// Gets the parent of the content item.
/// </summary>
/// <remarks>The parent of root content is <c>null</c>.</remarks>
[Obsolete("Please use IDocumentNavigationQueryService.TryGetParentKey() instead. Scheduled for removal in V16.")]
[Obsolete("Please use either the IPublishedContent.Parent<>() extension method in the Umbraco.Extensions namespace, or IDocumentNavigationQueryService if you only need keys. Scheduled for removal in V16.")]
IPublishedContent? Parent { get; }
/// <summary>
@@ -142,6 +142,6 @@ public interface IPublishedContent : IPublishedElement
/// <summary>
/// Gets the children of the content item that are available for the current culture.
/// </summary>
[Obsolete("Please use IDocumentNavigationQueryService.TryGetChildrenKeys() instead. Scheduled for removal in V16.")]
[Obsolete("Please use either the IPublishedContent.Children() extension method in the Umbraco.Extensions namespace, or IDocumentNavigationQueryService if you only need keys. Scheduled for removal in V16.")]
IEnumerable<IPublishedContent> Children { get; }
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Extensions;
@@ -9,6 +10,14 @@ namespace Umbraco.Cms.Core.PropertyEditors.Validators;
/// </summary>
public class DateTimeValidator : IValueValidator
{
/// <summary>
/// Validates if the value is a valid date/time
/// </summary>
/// <param name="value"></param>
/// <param name="valueType"></param>
/// <param name="dataTypeConfiguration"></param>
/// <param name="validationContext"></param>
/// <returns></returns>
public IEnumerable<ValidationResult> Validate(object? value, string? valueType, object? dataTypeConfiguration, PropertyValidationContext validationContext)
{
// don't validate if empty
@@ -17,10 +26,10 @@ public class DateTimeValidator : IValueValidator
yield break;
}
if (DateTime.TryParse(value.ToString(), out DateTime dt) == false)
if (DateTime.TryParse(value.ToString(), CultureInfo.InvariantCulture, out DateTime dt) == false)
{
yield return new ValidationResult(
string.Format("The string value {0} cannot be parsed into a DateTime", value),
$"The string value {value} cannot be parsed into a DateTime",
new[]
{
// we only store a single value for this editor so the 'member' or 'field'

View File

@@ -2406,6 +2406,8 @@ public class ContentService : RepositoryService, IContentService
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
var parentId = content.ParentId;
scope.WriteLock(Constants.Locks.ContentTree);
var originalPath = content.Path;
@@ -2438,6 +2440,14 @@ public class ContentService : RepositoryService, IContentService
movingToRecycleBinNotification));
Audit(AuditType.Move, userId, content.Id, "Moved to recycle bin");
// sort the children of the parent after deleting the content
IQuery<IContent> childQuery = Query<IContent>().Where(x => x.ParentId == parentId && x.Id != content.Id);
IEnumerable<IContent> children = _documentRepository.Get(childQuery);
if(children.Any())
{
Sort(children, userId);
}
scope.Complete();
}
@@ -2459,6 +2469,8 @@ public class ContentService : RepositoryService, IContentService
{
EventMessages eventMessages = EventMessagesFactory.Get();
var parentIdBeforeMove = content.ParentId;
if (content.ParentId == parentId)
{
return OperationResult.Succeed(eventMessages);
@@ -2523,6 +2535,14 @@ public class ContentService : RepositoryService, IContentService
Audit(AuditType.Move, userId, content.Id);
// sort the children of the old parent after moving the content
IQuery<IContent> childQuery = Query<IContent>().Where(x => x.ParentId == parentIdBeforeMove && x.Id != content.Id);
IEnumerable<IContent> children = _documentRepository.Get(childQuery);
if (children.Any())
{
Sort(children, userId);
}
scope.Complete();
return OperationResult.Succeed(eventMessages);
}

View File

@@ -1,4 +1,4 @@
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;

View File

@@ -1,4 +1,4 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentTypeEditing;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.Builders.Interfaces;

View File

@@ -0,0 +1,47 @@
using System.Globalization;
using NUnit.Framework;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors.Validators;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.Validators
{
/// <summary>
/// Unit test fixture for the DateTimeValidator class.
/// </summary>
[TestFixture]
public class DateTimeValidatorTests
{
/// <summary>
/// Tests that the DateTimeValidator is culture invariant.
/// </summary>
/// <param name="culture">The culture to set for the current thread.</param>
/// <param name="format">The date format to use for the test.</param>
[TestCase("en-US", "yyyy-MM-dd HH:mm:ss", TestName = "US Thread, DateTimeValidator")]
[TestCase("en-US", "dd-MM-yyyy HH:mm:ss", TestName = "US Thread, DateTimeValidator ar-SA format")]
[TestCase("ar-SA", "dd-MM-yyyy HH:mm:ss", TestName = "Arabian Saudi Thread, DateTimeValidator")]
[TestCase("ar-SA", "yyyy-MM-dd HH:mm:ss", TestName = "Arabian Saudi Thread, DateTimeValidator US format")]
public void DateTimeValidatorIsCultureInvariant(string culture, string format)
{
// Generate a date string using the specified format
var dateString = DateTime.Now.ToString(format);
// Set the current thread's culture and UI culture
var cultureInfo = new CultureInfo(culture);
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
// Create a new DateTimeValidator instance
var validator = new DateTimeValidator();
// Validate the date string
var validationResults = validator.Validate(
dateString,
"DATETIME",
new Dictionary<string, object>(),
PropertyValidationContext.Empty());
// Assert that there are no validation errors
CollectionAssert.IsEmpty(validationResults);
}
}
}