Merge remote-tracking branch 'origin/v10/10.0' into v10/contrib

This commit is contained in:
Bjarke Berg
2022-05-04 14:27:35 +02:00
273 changed files with 21126 additions and 8276 deletions

95
.gitignore vendored
View File

@@ -37,74 +37,69 @@ _NCrunch_*/
tools/NDepend/
[Tt]est[Rr]esult*
[Bb]uild[Ll]og.*
[sS]ource
[sS]andbox
[Ss]ource
[Ss]andbox
node_modules
lib-bower
*.psess
*.vspx
NDependOut/*
NDependOut/
QueryResult.htm
tools/docfx/*
tools/docfx/
# Ignore rule for clearing out Belle (avoid rebuilding all the time)
preserve.belle
# Ignore rule for output of generated documentation files from grunt docserve
src/Umbraco.Web.UI.Docs/api
src/Umbraco.Web.UI.Docs/package-lock.json
/src/Umbraco.Web.UI.Docs/api/
/src/Umbraco.Web.UI.Docs/package-lock.json
# Build
build.out/
build.tmp/
build/hooks/
build/temp/
/build.out/
/build.tmp/
/build/hooks/
/build/temp/
# Build output
build/docs.zip
build/ui-docs.zip
build/csharp-docs.zip
build/ApiDocs/*
build/ApiDocs/Output/*
src/ApiDocs/api/*
/build/docs.zip
/build/ui-docs.zip
/build/csharp-docs.zip
/build/ApiDocs/
/src/ApiDocs/api/
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/
# Environment specific data
src/Umbraco.Web.UI.Client/[Bb]uild/*
src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/TESTS-*.xml
src/Umbraco.Web.UI/[Uu]mbraco/[Dd]ata/*
src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ogs
src/Umbraco.Web.UI/[Uu]mbraco/[Mm]odels/*
src/Umbraco.Web.UI/appsettings.Development.json
src/Umbraco.Web.UI/appsettings.json
src/Umbraco.Web.UI/appsettings.Local.json
src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/assets/*
src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/js/*
src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/lib/*
src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/views/*
src/Umbraco.Web.UI/wwwroot/Media/*
src/Umbraco.Web.UI/Smidge/
src/Umbraco.Web.UI/App_Code/
src/Umbraco.Web.UI/App_Plugins/
src/Umbraco.Web.UI/Views/
!src/Umbraco.Web.UI/Views/Partials/blocklist/
!src/Umbraco.Web.UI/Views/Partials/grid/
!src/Umbraco.Web.UI/Views/_ViewImports.cshtml
/src/Umbraco.Web.UI.Client/[Bb]uild/
/src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
/src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
/src/Umbraco.Web.UI.Client/TESTS-*.xml
/src/Umbraco.Web.UI/wwwroot/[Mm]edia/
/src/Umbraco.Web.UI/App_Code/
/src/Umbraco.Web.UI/App_Plugins/
/src/Umbraco.Web.UI/[Uu]mbraco/[Dd]ata/
/src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ogs/
/src/Umbraco.Web.UI/[Uu]mbraco/[Mm]odels/
/src/Umbraco.Web.UI/Views/
!/src/Umbraco.Web.UI/Views/Partials/blocklist/
!/src/Umbraco.Web.UI/Views/Partials/grid/
!/src/Umbraco.Web.UI/Views/_ViewImports.cshtml
/src/Umbraco.Web.UI/appsettings.json
/src/Umbraco.Web.UI/appsettings.Development.json
/src/Umbraco.Web.UI/appsettings.Local.json
# Tests
cypress.env.json
tests/Umbraco.Tests.AcceptanceTest/cypress/screenshots/
tests/Umbraco.Tests.AcceptanceTest/cypress/support/chainable.ts
tests/Umbraco.Tests.AcceptanceTest/cypress/videos/
tests/Umbraco.Tests.Integration.SqlCe/DatabaseContextTests.sdf
tests/Umbraco.Tests.Integration.SqlCe/umbraco/Data/TEMP/
tests/Umbraco.Tests.Integration/appsettings.Tests.Local.json
tests/Umbraco.Tests.Integration/TEMP/*
tests/Umbraco.Tests.Integration/umbraco/Data/
tests/Umbraco.Tests.Integration/umbraco/logs/
tests/Umbraco.Tests.Integration/Views/
tests/Umbraco.Tests.UnitTests/umbraco/Data/TEMP/
/tests/Umbraco.Tests.AcceptanceTest/cypress/screenshots/
/tests/Umbraco.Tests.AcceptanceTest/cypress/support/chainable.ts
/tests/Umbraco.Tests.AcceptanceTest/cypress/videos/
/tests/Umbraco.Tests.Integration.SqlCe/DatabaseContextTests.sdf
/tests/Umbraco.Tests.Integration.SqlCe/[Uu]mbraco/[Dd]ata/TEMP/
/tests/Umbraco.Tests.Integration/appsettings.Tests.Local.json
/tests/Umbraco.Tests.Integration/TEMP/
/tests/Umbraco.Tests.Integration/[Uu]mbraco/[Dd]ata/
/tests/Umbraco.Tests.Integration/[Uu]mbraco/[Ll]ogs/
/tests/Umbraco.Tests.Integration/Views/
/tests/Umbraco.Tests.UnitTests/[Uu]mbraco/[Dd]ata/TEMP/
# Ignore auto-generated schema
src/Umbraco.Web.UI/umbraco/config/appsettings-schema.json
/src/Umbraco.Web.UI/[Uu]mbraco/config/appsettings-schema.json

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="4.1.0">
<id>Umbraco.Cms.StaticAssets</id>
<version>9.0.0</version>
<title>Umbraco Cms Static Assets</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<license type="expression">MIT</license>
<projectUrl>https://umbraco.com/</projectUrl>
<iconUrl>https://umbraco.com/dist/nuget/logo-small.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the static assets that is required to run Umbraco CMS.</description>
<summary>Contains the static assets that is required to run Umbraco CMS.</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
</dependencies>
</metadata>
<files>
<!-- Content -->
<file src="$BuildTmp$\WebApp\wwwroot\umbraco\**\*.*" target="content\wwwroot\umbraco" />
<file src="$BuildTmp$\WebApp\umbraco\**\*.*" target="content\umbraco" />
<!-- UmbracoCms props and targets used to copy the content into the solution -->
<file src="buildTransitive\**" target="buildTransitive\" />
</files>
</package>

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="4.1.0">
<id>Umbraco.Cms</id>
<version>9.0.0</version>
<version>10.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
@@ -24,12 +24,8 @@
<dependency id="Umbraco.Cms.Persistence.Sqlite" version="[$version$]" />
</group>
</dependencies>
<!--
We can't use content files, as the files need to be copied into the solution, links/shortcuts to the files
are not good enough
-->
<contentFiles />
</metadata>
<files>
</files>
<files>
<file src="buildTransitive\Umbraco.Cms.props" target="buildTransitive" />
</files>
</package>

View File

@@ -1,91 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ContentFilesPath>$(MSBuildThisFileDirectory)..\content\umbraco\**\*.*</ContentFilesPath>
<ContentWwwrootFilesPath>$(MSBuildThisFileDirectory)..\content\wwwroot\umbraco\**\*.*</ContentWwwrootFilesPath>
<UmbracoWwwrootName Condition="'$(UmbracoWwwrootName)' == ''">umbraco</UmbracoWwwrootName>
</PropertyGroup>
<Target Name="CopyUmbracoAssets" BeforeTargets="BeforeBuild">
<ItemGroup>
<ContentFiles Include="$(ContentFilesPath)" />
<ContentWwwrootFiles Include="$(ContentWwwrootFilesPath)" />
</ItemGroup>
<Message Text="Copying Umbraco content files: $(ContentFilesPath) - #@(ContentFiles->Count()) files" Importance="high" />
<Message Text="Copying Umbraco wwwroot content files: $(ContentWwwrootFilesPath) - #@(ContentWwwrootFiles->Count()) files" Importance="high" />
<Copy
SourceFiles="@(ContentFiles)"
DestinationFiles="@(ContentFiles->'$(MSBuildProjectDirectory)\umbraco\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
<Copy
SourceFiles="@(ContentWwwrootFiles)"
DestinationFiles="@(ContentWwwrootFiles->'$(MSBuildProjectDirectory)\wwwroot\$(UmbracoWwwrootName)\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
</Target>
<Target Name="IncludeAppPluginsContent" BeforeTargets="GetCopyToOutputDirectoryItems;GetCopyToPublishDirectoryItems;">
<ItemGroup>
<_AppPluginsFiles Include="App_Plugins\**" />
<ContentWithTargetPath
Include="@(_AppPluginsFiles)"
Exclude="@(ContentWithTargetPath)"
TargetPath="%(Identity)"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="PreserveNewest"/>
</ItemGroup>
</Target>
<!--
The set of files to publish is generated really early and doesn't currently account for files added by targets e.g. BeforeBuild.
A fix was put in place in Web SDK to update for wwwwroot in case someone runs npm build etc in a target, we're borrowing their trick.
https://github.com/dotnet/sdk/blob/e2b2b1a4ac56c955b84d62fe71cda3b6f258b42b/src/WebSdk/Publish/Targets/ComputeTargets/Microsoft.NET.Sdk.Publish.ComputeFiles.targets
-->
<Target Name="IncludeUmbracoFolderContent" BeforeTargets="GetCopyToOutputDirectoryItems;GetCopyToPublishDirectoryItems;">
<ItemGroup>
<_UmbracoFolderFiles Include="umbraco\config\**" />
<_UmbracoFolderFiles Include="umbraco\PartialViewMacros\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoBackOffice\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoInstall\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" />
<_UmbracoFolderFiles Include="umbraco\Licenses\**" />
<!-- This could be handled in deploy if it's not already -->
<_UmbracoFolderFiles Include="umbraco\Deploy\**" />
<ContentWithTargetPath
Include="@(_UmbracoFolderFiles)"
Exclude="@(ContentWithTargetPath)"
TargetPath="%(Identity)"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="PreserveNewest"/>
</ItemGroup>
</Target>
<Target Name="ClearUmbracoAssets" BeforeTargets="Clean">
<ItemGroup>
<UmbracoConfigPackageDir Include="$(MSBuildProjectDirectory)\umbraco\config\" />
<UmbracoPartialViewMacrosPackageDir Include="$(MSBuildProjectDirectory)\umbraco\PartialViewMacros\" />
<UmbracoUmbracoBackOfficeMacrosDir Include="$(MSBuildProjectDirectory)\umbraco\UmbracoBackOffice\" />
<UmbracoUmbracoInstallDir Include="$(MSBuildProjectDirectory)\umbraco\UmbracoInstall\" />
<UmbracoUmbracoWebsiteMacrosDir Include="$(MSBuildProjectDirectory)\umbraco\UmbracoWebsite\" />
<WwwrootUmbracoPackageDir Include="$(MSBuildProjectDirectory)\wwwroot\$(UmbracoWwwrootName)\" />
</ItemGroup>
<Message Text="Clear old umbraco data" Importance="high" />
<RemoveDir Directories="@(UmbracoConfigPackageDir)" />
<RemoveDir Directories="@(UmbracoPartialViewMacrosPackageDir)" />
<RemoveDir Directories="@(UmbracoUmbracoBackOfficeMacrosDir)" />
<RemoveDir Directories="@(UmbracoUmbracoInstallDir)" />
<RemoveDir Directories="@(UmbracoUmbracoWebsiteMacrosDir)" />
<RemoveDir Directories="@(WwwrootUmbracoPackageDir)" />
</Target>
<Target Name="IncludeUmbracoRazorFiles" BeforeTargets="ResolveRazorGenerateInputs">
<ItemGroup>
<Content Include="$(MSBuildProjectDirectory)\umbraco\**\*.cshtml" Exclude="@(Content)" />
</ItemGroup>
</Target>
</Project>

View File

@@ -271,7 +271,7 @@ stages:
gulpFile: src\Umbraco.Web.UI.Client\gulpfile.js
targets: build
workingDirectory: src\Umbraco.Web.UI.Client
- powershell: Start-Process -FilePath "dotnet" -ArgumentList "run", "-p", "src\Umbraco.Web.UI\Umbraco.Web.UI.csproj"
- powershell: Start-Process -FilePath "dotnet" -ArgumentList "run", "-p", "src\Umbraco.Web.UI\Umbraco.Web.UI.csproj /Umbraco:CMS:Global:Id=0000000-0000-0000-0000-000000000042"
displayName: dotnet run
# - powershell: dotnet run --no-build -p .\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj
# displayName: dotnet run
@@ -375,7 +375,7 @@ stages:
displayName: dotnet run
inputs:
targetType: 'inline'
script: 'nohup dotnet run --no-build -p ./src/Umbraco.Web.UI/ > $(Build.ArtifactStagingDirectory)/dotnet_run_log_linux.txt &'
script: 'nohup dotnet run --no-build -p ./src/Umbraco.Web.UI/ /Umbraco:CMS:Global:Id=0000000-0000-0000-0000-000000000042 > $(Build.ArtifactStagingDirectory)/dotnet_run_log_linux.txt &'
- task: Bash@3
displayName: Generate Cypress.env.json
inputs:

View File

@@ -192,7 +192,6 @@
$this.RemoveFile($excludeFiles)
# copy rest of the files into WebApp
$this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Web.UI\umbraco", "*", "$($this.BuildTemp)\WebApp\umbraco")
$excludeUmbracoDirs = @("$($this.BuildTemp)\WebApp\umbraco\lib","$($this.BuildTemp)\WebApp\umbraco\Data","$($this.BuildTemp)\WebApp\umbraco\Logs")
$this.RemoveDirectory($excludeUmbracoDirs)
$this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Web.UI\Views", "*", "$($this.BuildTemp)\WebApp\Views")
@@ -301,13 +300,6 @@
$_.CreationTime = $_.CreationTime.AddHours(-11)
$_.LastWriteTime = $_.LastWriteTime.AddHours(-11)
}
# copy Belle
Write-Host "Copy Belle"
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\assets", "*", "$tmp\WebApp\wwwroot\umbraco\assets")
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\js", "*", "$tmp\WebApp\wwwroot\umbraco\js")
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\lib", "*", "$tmp\WebApp\wwwroot\umbraco\lib")
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\views", "*", "$tmp\WebApp\wwwroot\umbraco\views")
})
@@ -365,12 +357,6 @@
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cms.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.StaticAssets.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsstaticassets.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.StaticAssets." }
&$this.BuildEnv.NuGet Pack "$templates\Umbraco.Templates.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `

View File

@@ -5,7 +5,7 @@
<PropertyGroup>
<Version>10.0.0</Version>
<AssemblyVersion>10.0.0</AssemblyVersion>
<InformationalVersion>10.0.0-rc</InformationalVersion>
<InformationalVersion>10.0.0-rc1</InformationalVersion>
<FileVersion>10.0.0</FileVersion>
<LangVersion Condition="'$(LangVersion)' == ''">10.0</LangVersion>
<NeutralLanguage>en-US</NeutralLanguage>
@@ -19,6 +19,9 @@
<PackageTags>umbraco</PackageTags>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/umbraco/umbraco-cms</RepositoryUrl>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup>

View File

@@ -16,7 +16,7 @@ namespace JsonSchema
/// <summary>
/// Gets or sets the Umbraco
/// </summary>
public UmbracoDefinition Umbraco { get; set; }
public UmbracoDefinition? Umbraco { get; set; }
/// <summary>
/// Configuration of Umbraco CMS and packages
@@ -24,76 +24,76 @@ namespace JsonSchema
internal class UmbracoDefinition
{
// ReSharper disable once InconsistentNaming
public CmsDefinition CMS { get; set; }
public CmsDefinition? CMS { get; set; }
public FormsDefinition Forms { get; set; }
public FormsDefinition? Forms { get; set; }
public DeployDefinition Deploy { get; set; }
public DeployDefinition? Deploy { get; set; }
/// <summary>
/// Configurations for the Umbraco CMS
/// </summary>
public class CmsDefinition
{
public ActiveDirectorySettings ActiveDirectory { get; set; }
public ActiveDirectorySettings? ActiveDirectory { get; set; }
public ContentSettings Content { get; set; }
public ContentSettings? Content { get; set; }
public ExceptionFilterSettings ExceptionFilter { get; set; }
public ExceptionFilterSettings? ExceptionFilter { get; set; }
public ModelsBuilderSettings ModelsBuilder { get; set; }
public ModelsBuilderSettings? ModelsBuilder { get; set; }
public GlobalSettings Global { get; set; }
public GlobalSettings? Global { get; set; }
public HealthChecksSettings HealthChecks { get; set; }
public HealthChecksSettings? HealthChecks { get; set; }
public HostingSettings Hosting { get; set; }
public HostingSettings? Hosting { get; set; }
public ImagingSettings Imaging { get; set; }
public ImagingSettings? Imaging { get; set; }
public IndexCreatorSettings Examine { get; set; }
public IndexCreatorSettings? Examine { get; set; }
public KeepAliveSettings KeepAlive { get; set; }
public KeepAliveSettings? KeepAlive { get; set; }
public LoggingSettings Logging { get; set; }
public LoggingSettings? Logging { get; set; }
public MemberPasswordConfigurationSettings MemberPassword { get; set; }
public MemberPasswordConfigurationSettings? MemberPassword { get; set; }
public NuCacheSettings NuCache { get; set; }
public NuCacheSettings? NuCache { get; set; }
public RequestHandlerSettings RequestHandler { get; set; }
public RequestHandlerSettings? RequestHandler { get; set; }
public RuntimeSettings Runtime { get; set; }
public RuntimeSettings? Runtime { get; set; }
public SecuritySettings Security { get; set; }
public SecuritySettings? Security { get; set; }
public TourSettings Tours { get; set; }
public TourSettings? Tours { get; set; }
public TypeFinderSettings TypeFinder { get; set; }
public TypeFinderSettings? TypeFinder { get; set; }
public UserPasswordConfigurationSettings UserPassword { get; set; }
public UserPasswordConfigurationSettings? UserPassword { get; set; }
public WebRoutingSettings WebRouting { get; set; }
public WebRoutingSettings? WebRouting { get; set; }
public UmbracoPluginSettings Plugins { get; set; }
public UmbracoPluginSettings? Plugins { get; set; }
public UnattendedSettings Unattended { get; set; }
public UnattendedSettings? Unattended { get; set; }
public RichTextEditorSettings RichTextEditor { get; set; }
public RichTextEditorSettings? RichTextEditor { get; set; }
public RuntimeMinificationSettings RuntimeMinification { get; set; }
public RuntimeMinificationSettings? RuntimeMinification { get; set; }
public BasicAuthSettings BasicAuth { get; set; }
public BasicAuthSettings? BasicAuth { get; set; }
public PackageMigrationSettings PackageMigration { get; set; }
public PackageMigrationSettings? PackageMigration { get; set; }
public LegacyPasswordMigrationSettings LegacyPasswordMigration { get; set; }
public LegacyPasswordMigrationSettings? LegacyPasswordMigration { get; set; }
public ContentDashboardSettings ContentDashboard { get; set; }
public ContentDashboardSettings? ContentDashboard { get; set; }
public HelpPageSettings HelpPage { get; set; }
public HelpPageSettings? HelpPage { get; set; }
public InstallDefaultDataSettings DefaultDataCreation { get; set; }
public InstallDefaultDataSettings? DefaultDataCreation { get; set; }
}
/// <summary>
@@ -101,24 +101,24 @@ namespace JsonSchema
/// </summary>
public class FormsDefinition
{
public FormDesignSettings FormDesign { get; set; }
public FormDesignSettings? FormDesign { get; set; }
public PackageOptionSettings Options { get; set; }
public PackageOptionSettings? Options { get; set; }
public Umbraco.Forms.Core.Configuration.SecuritySettings Security { get; set; }
public Umbraco.Forms.Core.Configuration.SecuritySettings? Security { get; set; }
public FieldTypesDefinition FieldTypes { get; set; }
public FieldTypesDefinition? FieldTypes { get; set; }
/// <summary>
/// Configurations for the Umbraco Forms Field Types
/// </summary>
public class FieldTypesDefinition
{
public DatePickerSettings DatePicker { get; set; }
public DatePickerSettings? DatePicker { get; set; }
public Recaptcha2Settings Recaptcha2 { get; set; }
public Recaptcha2Settings? Recaptcha2 { get; set; }
public Recaptcha3Settings Recaptcha3 { get; set; }
public Recaptcha3Settings? Recaptcha3 { get; set; }
}
}
@@ -127,11 +127,11 @@ namespace JsonSchema
/// </summary>
public class DeployDefinition
{
public DeploySettings Settings { get; set; }
public DeploySettings? Settings { get; set; }
public DeployProjectConfig Project { get; set; }
public DeployProjectConfig? Project { get; set; }
public DebugSettings Debug { get; set; }
public DebugSettings? Debug { get; set; }
}
}
}

View File

@@ -8,6 +8,6 @@ namespace JsonSchema
{
internal class NamespacePrefixedSchemaNameGenerator : DefaultSchemaNameGenerator
{
public override string Generate(Type type) => type.Namespace.Replace(".", string.Empty) + base.Generate(type);
public override string Generate(Type type) => type.Namespace?.Replace(".", string.Empty) + base.Generate(type);
}
}

View File

@@ -8,6 +8,6 @@ namespace JsonSchema
internal class Options
{
[Option('o', "outputFile", Required = false, HelpText = "Set path of the output file.", Default = "../../../../Umbraco.Web.UI/umbraco/config/appsettings-schema.json")]
public string OutputFile { get; set; }
public string OutputFile { get; set; } = null!;
}
}

View File

@@ -31,7 +31,7 @@ namespace JsonSchema
var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, options.OutputFile));
Console.WriteLine("Path to use {0}", path);
Directory.CreateDirectory(Path.GetDirectoryName(path));
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
Console.WriteLine("Ensured directory exists");
await File.WriteAllTextAsync(path, schema);

View File

@@ -43,14 +43,14 @@ namespace JsonSchema
var result = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<JObject>(result);
return JsonConvert.DeserializeObject<JObject>(result)!;
}
private JObject GenerateUmbracoSchema()
{
NJsonSchema.JsonSchema schema = _innerGenerator.Generate(typeof(AppSettings));
return JsonConvert.DeserializeObject<JObject>(schema.ToJson());
return JsonConvert.DeserializeObject<JObject>(schema.ToJson())!;
}
}
}

View File

@@ -2,9 +2,6 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>Umbraco.Cms.Persistence.SqlServer</PackageId>
<Title>Umbraco.Cms.Persistence.SqlServer</Title>
<Description>Adds support for SQL Server to Umbraco CMS.</Description>

View File

@@ -2,9 +2,6 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>Umbraco.Cms.Persistence.Sqlite</PackageId>
<Title>Umbraco.Cms.Persistence.Sqlite</Title>
<Description>Adds support for SQLite to Umbraco CMS.</Description>

View File

@@ -0,0 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<PackageId>Umbraco.Cms.StaticAssets</PackageId>
<Description>Contains the static assets that is required to run Umbraco CMS.</Description>
<StaticWebAssetBasePath>/</StaticWebAssetBasePath>
</PropertyGroup>
<ItemGroup>
<None Include="buildTransitive\**\*.*">
<Pack>true</Pack>
<PackagePath>buildTransitive</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" PrivateAssets="All" />
<ProjectReference Include="..\Umbraco.Web.Website\Umbraco.Web.Website.csproj" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup>
<BellePath>$(ProjectDir)wwwroot/umbraco</BellePath>
</PropertyGroup>
<Target Name="CheckPreconditions" BeforeTargets="Build">
<Message Text="-CheckPreconditions-" Importance="high" />
<Message Text="BellePath: $(BellePath)" Importance="high" />
<!-- Build Belle, if building is Visual Studio and the build folder does not exist yet -->
<Message Text="Skip Belle because UmbracoBuild is '$(UmbracoBuild)' (this is not Visual Studio)." Importance="High" Condition="'$(UmbracoBuild)' != ''" />
<Message Text="Skip Belle because $(BellePath) exists." Importance="High" Condition="Exists('$(BellePath)')" />
<Message Text="Build Belle because UmbracoBuild is empty (this is Visual Studio), and $(BellePath) does not exist." Importance="High" Condition="!Exists('$(BellePath)') and '$(UmbracoBuild)' == ''" />
<CallTarget Targets="BelleBuild" Condition="!Exists('$(BellePath)') and '$(UmbracoBuild)' == ''" />
<Message Text="Skip JsonSchema generation because $(JsonSchemaPath) exists." Importance="High" Condition="Exists('$(JsonSchemaPath)')" />
<Message Text="Generate the appsettings json schema." Importance="High" Condition="!Exists('$(JsonSchemaPath)') and '$(UmbracoBuild)' == ''" />
</Target>
<Target Name="BelleBuild">
<Exec WorkingDirectory="$(ProjectDir)/../Umbraco.Web.UI.Client/" Command="npm ci --no-fund --no-audit --prefer-offline" />
<Exec WorkingDirectory="$(ProjectDir)/../Umbraco.Web.UI.Client/" Command="npm run build:skip-tests" />
</Target>
<!-- Clean Belle when cleaning and rebuilding, but only in Visual Studio -->
<Target Name="CleanPreconditions" AfterTargets="Clean" Condition="'$(UmbracoBuild)' == ''">
<Message Text="-CleanPreconditions-" Importance="high" />
<Message Text="Nothing to clean, as $(BellePath) does not exist." Importance="High" Condition="!Exists('$(BellePath)')" />
<Message Text="Not cleaning (found src/preserve.belle)." Importance="High" Condition="Exists('$(BellePath)') and Exists('$(SolutionDir)preserve.belle')" />
<Message Text="Remove $(BellePath)." Importance="High" Condition="Exists('$(BellePath)') and !Exists('$(SolutionDir)preserve.belle')" />
<ItemGroup>
<BelleLib Include="$(BellePath)" />
</ItemGroup>
<RemoveDir Directories="@(BelleLib)" Condition="Exists('$(BellePath)') and !Exists('$(SolutionDir)preserve.belle')" />
<Message Text="Remove $(JsonSchemaPath)." Importance="High" Condition="Exists('$(JsonSchemaPath)') and !Exists('$(SolutionDir)preserve.jsonschema')" />
<Delete Files="$(JsonSchemaPath)" Condition="Exists('$(JsonSchemaPath)') and !Exists('$(SolutionDir)preserve.jsonschema')" />
</Target>
<!--
The set of files to publish is generated really early and doesn't currently account for files added by targets e.g. BeforeBuild.
A fix was put in place in Web SDK to update for wwwwroot in case someone runs npm build etc in a target, we're borrowing their trick.
https://github.com/dotnet/sdk/blob/e2b2b1a4ac56c955b84d62fe71cda3b6f258b42b/src/WebSdk/Publish/Targets/ComputeTargets/Microsoft.NET.Sdk.Publish.ComputeFiles.targets
-->
<Target Name="IncludeUmbracoFolderContent" BeforeTargets="GetCopyToOutputDirectoryItems;GetCopyToPublishDirectoryItems;">
<ItemGroup>
<_UmbracoFolderFiles Include="umbraco\config\**" />
<_UmbracoFolderFiles Include="umbraco\PartialViewMacros\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoBackOffice\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoInstall\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" />
<_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" />
<_UmbracoFolderFiles Include="umbraco\Licenses\**" />
<ContentWithTargetPath Include="@(_UmbracoFolderFiles)" Exclude="@(ContentWithTargetPath)" TargetPath="%(Identity)" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
</Target>
</Project>

View File

@@ -59,15 +59,15 @@
<script type="text/javascript">
document.angularReady = function (app) {
@await Html.AngularValueExternalLoginInfoScriptAsync(externalLogins, ViewData.GetExternalSignInProviderErrors())
@Html.AngularValueResetPasswordCodeInfoScript(ViewData[ViewDataExtensions.TokenPasswordResetCode])
@await Html.AngularValueExternalLoginInfoScriptAsync(externalLogins, ViewData.GetExternalSignInProviderErrors()!)
@Html.AngularValueResetPasswordCodeInfoScript(ViewData[ViewDataExtensions.TokenPasswordResetCode]!)
}
</script>
@*And finally we can load in our angular app*@
<script type="text/javascript" src="lib/lazyload-js/LazyLoad.min.js"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice", null, hostingEnvironment, umbracoVersion, runtimeMinifier)"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice", null!, hostingEnvironment, umbracoVersion, runtimeMinifier)"></script>
</body>
</html>

View File

@@ -120,8 +120,8 @@
<script>
document.angularReady = function(app) {
@await Html.AngularValueExternalLoginInfoScriptAsync(externalLogins, ViewData.GetExternalSignInProviderErrors())
@Html.AngularValueResetPasswordCodeInfoScript(ViewData[ViewDataExtensions.TokenPasswordResetCode])
@await Html.AngularValueExternalLoginInfoScriptAsync(externalLogins, ViewData.GetExternalSignInProviderErrors()!)
@Html.AngularValueResetPasswordCodeInfoScript(ViewData[ViewDataExtensions.TokenPasswordResetCode]!)
@await Html.AngularValueTinyMceAssetsAsync(runtimeMinifier)
//required for the noscript trick
document.getElementById("mainwrapper").style.display = "inherit";
@@ -129,7 +129,7 @@
</script>
<script src="@WebPath.Combine(backOfficePath.TrimStart("~"), "/lib/lazyload-js/LazyLoad.min.js")"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice", null, hostingEnvironment, umbracoVersion, runtimeMinifier)"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice", null!, hostingEnvironment, umbracoVersion, runtimeMinifier)"></script>
@if (isDebug)
{

View File

@@ -108,7 +108,7 @@
@await Html.BareMinimumServerVariablesScriptAsync(BackOfficeServerVariables)
<script src="../lib/lazyload-js/LazyLoad.min.js"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "Preview", null, HostingEnvironment, UmbracoVersion, RuntimeMinifier)"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "Preview", null!, HostingEnvironment, UmbracoVersion, RuntimeMinifier)"></script>
</body>
</html>

View File

@@ -69,7 +69,7 @@
"installApiBaseUrl": "@ViewData.GetInstallApiBaseUrl()",
"umbracoBaseUrl": "@ViewData.GetUmbracoBaseFolder()",
"application": {
version: "@ViewData.GetUmbracoVersion().Major"
version: "@ViewData.GetUmbracoVersion()?.Major"
}
};
</script>

View File

@@ -42,8 +42,8 @@
@if (hostingEnvironment.IsDebugMode)
{
var reason = (string)Context.Items["reason"];
var message = (string)Context.Items["message"];
var reason = (string?)Context.Items["reason"];
var message = (string?)Context.Items["message"];
if (!reason.IsNullOrWhiteSpace())
{

View File

@@ -42,9 +42,9 @@ namespace Umbraco.Cms.Core.Cache
persistDeleted(entity);
}
public TEntity[]? GetAll(TId[]? ids, Func<TId[]?, IEnumerable<TEntity>?> performGetAll)
public TEntity[] GetAll(TId[]? ids, Func<TId[]?, IEnumerable<TEntity>?> performGetAll)
{
return performGetAll(ids)?.ToArray();
return performGetAll(ids)?.ToArray() ?? Array.Empty<TEntity>();
}
public void ClearAll()

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
namespace Umbraco.Core.Collections
namespace Umbraco.Cms.Core.Collections
{
/// <summary>
/// Collection that can be both a queue and a stack.

View File

@@ -29,8 +29,13 @@ namespace Umbraco.Cms.Core.Composing
/// Based on a type we'll check if it is IEnumerable{T} (or similar) and if so we'll return a List{T}, this will also deal with array types and return List{T} for those too.
/// If it cannot be done, null is returned.
/// </summary>
public static IList? CreateGenericEnumerableFromObject(object obj)
public static IList? CreateGenericEnumerableFromObject(object? obj)
{
if (obj is null)
{
return null;
}
var type = obj.GetType();
if (type.IsGenericType)

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Cms.Core.Composing
private readonly Dictionary<CompositeTypeTypeKey, TypeList> _types = new ();
private readonly object _locko = new ();
private IEnumerable<Assembly> _assemblies;
private IEnumerable<Assembly>? _assemblies;
/// <summary>
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
@@ -121,11 +121,11 @@ namespace Umbraco.Cms.Core.Composing
// internal for tests
[Obsolete("This will be removed in a future version.")]
public Dictionary<(string, string), IEnumerable<string>> ReadCache() => null;
public Dictionary<(string, string), IEnumerable<string>>? ReadCache() => null;
// internal for tests
[Obsolete("This will be removed in a future version.")]
public string GetTypesListFilePath() => null;
public string? GetTypesListFilePath() => null;
// internal for tests
[Obsolete("This will be removed in a future version.")]
@@ -340,7 +340,7 @@ namespace Umbraco.Cms.Core.Composing
// check if the TypeList already exists, if so return it, if not we'll create it
var tobject = typeof(object); // CompositeTypeTypeKey does not support null values
var listKey = new CompositeTypeTypeKey(baseType ?? tobject, attributeType ?? tobject);
TypeList typeList = null;
TypeList? typeList = null;
if (cache)
{
@@ -411,7 +411,7 @@ namespace Umbraco.Cms.Core.Composing
/// </summary>
public void Add(Type type)
{
if (BaseType.IsAssignableFrom(type) == false)
if (BaseType?.IsAssignableFrom(type) == false)
throw new ArgumentException("Base type " + BaseType + " is not assignable from type " + type + ".", nameof(type));
_types.Add(type);
}

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
internal const bool StaticUseHttps = false;
internal const int StaticVersionCheckPeriod = 7;
internal const string StaticUmbracoPath = Constants.System.DefaultUmbracoPath;
internal const string StaticIconsPath = "~/umbraco/assets/icons";
internal const string StaticIconsPath = "umbraco/assets/icons";
internal const string StaticUmbracoCssPath = "~/css";
internal const string StaticUmbracoScriptsPath = "~/scripts";
internal const string StaticUmbracoMediaPath = "~/media";

View File

@@ -1865,6 +1865,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
</area>
<area alias="languages">
<key alias="addLanguage">Add language</key>
<key alias="culture">ISO code</key>
<key alias="mandatoryLanguage">Mandatory language</key>
<key alias="mandatoryLanguageHelp">Properties on this language have to be filled out before the node can be
published.

View File

@@ -1928,6 +1928,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
</area>
<area alias="languages">
<key alias="addLanguage">Add language</key>
<key alias="culture">ISO code</key>
<key alias="mandatoryLanguage">Mandatory language</key>
<key alias="mandatoryLanguageHelp">Properties on this language have to be filled out before the node can be
published.
@@ -2870,5 +2871,29 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
<area alias="analytics">
<key alias="consentForAnalytics">Consent for analytics</key>
<key alias="analyticsLevelSavedSuccess">Analytics level saved!</key>
<key alias="analyticsDescription">
<![CDATA[
In order to improve Umbraco and add new functionality based on as relevant information as possible,
<br>we would like to collect system- and usage information from your installation.
<br>Aggregate data will be shared on a regular basis as well as learnings from these metrics.
<br>Hopefully, you will help us collect some valuable data.
<br>
<br>We <b>WILL NOT</b> collect any personal data such as content, code, user information, and all data will be fully anonymized.
]]>
</key>
<key alias="minimalLevelDescription">We will only send an anonymized site ID to let us know that the site exists.</key>
<key alias="basicLevelDescription">We will send an anonymized site ID, umbraco version, and packages installed</key>
<key alias="detailedLevelDescription">
<![CDATA[
<br> We will send:
<br>- Anonymized site ID, umbraco version, and packages installed.
<br>- Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.
<br>- System information: Webserver, server OS, server framework, server OS language, and database provider.
<br>- Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.
<br>
<br><i>We might change what we send on the Detailed level in the future. If so, it will be listed above.
<br>By choosing "Detailed" you agree to current and future anonymized information being collected.</i>
]]>
</key>
</area>
</language>

View File

@@ -128,7 +128,7 @@ namespace Umbraco.Cms.Core.Events
return AdditionalData != null ? AdditionalData.GetHashCode() : 0;
}
public static bool operator ==(CancellableEventArgs left, CancellableEventArgs right)
public static bool operator ==(CancellableEventArgs? left, CancellableEventArgs? right)
{
return Equals(left, right);
}

View File

@@ -99,7 +99,7 @@ namespace Umbraco.Cms.Core.Events
/// </summary>
public IEnumerable<TEntity> DeletedEntities
{
get => EventObject;
get => EventObject ?? Enumerable.Empty<TEntity>();
set => EventObject = value;
}
@@ -108,14 +108,14 @@ namespace Umbraco.Cms.Core.Events
/// </summary>
public List<string> MediaFilesToDelete { get; private set; }
public bool Equals(DeleteEventArgs<TEntity> other)
public bool Equals(DeleteEventArgs<TEntity>? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && MediaFilesToDelete.SequenceEqual(other.MediaFilesToDelete);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
@@ -166,14 +166,14 @@ namespace Umbraco.Cms.Core.Events
/// </summary>
public int Id { get; private set; }
public bool Equals(DeleteEventArgs other)
public bool Equals(DeleteEventArgs? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && Id == other.Id;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;

View File

@@ -27,11 +27,11 @@ namespace Umbraco.Cms.Core.Events
public class EventDefinition<TEventArgs> : EventDefinitionBase
{
private readonly EventHandler<TEventArgs?> _trackedEvent;
private readonly EventHandler<TEventArgs> _trackedEvent;
private readonly object _sender;
private readonly TEventArgs? _args;
private readonly TEventArgs _args;
public EventDefinition(EventHandler<TEventArgs?> trackedEvent, object sender, TEventArgs? args, string? eventName = null)
public EventDefinition(EventHandler<TEventArgs> trackedEvent, object sender, TEventArgs args, string? eventName = null)
: base(sender, args, eventName)
{
_trackedEvent = trackedEvent;
@@ -50,11 +50,11 @@ namespace Umbraco.Cms.Core.Events
public class EventDefinition<TSender, TEventArgs> : EventDefinitionBase
{
private readonly TypedEventHandler<TSender?, TEventArgs> _trackedEvent;
private readonly TSender? _sender;
private readonly TypedEventHandler<TSender, TEventArgs> _trackedEvent;
private readonly TSender _sender;
private readonly TEventArgs _args;
public EventDefinition(TypedEventHandler<TSender?, TEventArgs> trackedEvent, TSender? sender, TEventArgs args, string? eventName = null)
public EventDefinition(TypedEventHandler<TSender, TEventArgs> trackedEvent, TSender sender, TEventArgs args, string? eventName = null)
: base(sender, args, eventName)
{
_trackedEvent = trackedEvent;

View File

@@ -27,7 +27,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string name = null);
bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string? name = null);
/// <summary>
/// Dispatches a cancelable event.
@@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string name = null)
bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? name = null)
where TArgs : CancellableEventArgs;
/// <summary>
@@ -50,7 +50,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string name = null)
bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? name = null)
where TArgs : CancellableEventArgs;
/// <summary>
@@ -61,7 +61,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string name = null);
void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string? name = null);
/// <summary>
/// Dispatches an event.
@@ -71,7 +71,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string name = null);
void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? name = null);
/// <summary>
/// Dispatches an event.
@@ -81,7 +81,7 @@ namespace Umbraco.Cms.Core.Events
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string name = null);
void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? name = null);
/// <summary>
/// Notifies the dispatcher that the scope is exiting.

View File

@@ -11,14 +11,14 @@ namespace Umbraco.Cms.Core.Events
/// whatever happens, and the transaction could roll back in the end.</remarks>
internal class PassThroughEventDispatcher : IEventDispatcher
{
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string? eventName = null)
{
if (eventHandler == null) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
@@ -26,7 +26,7 @@ namespace Umbraco.Cms.Core.Events
return args.Cancel;
}
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
@@ -34,17 +34,17 @@ namespace Umbraco.Cms.Core.Events
return args.Cancel;
}
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string? eventName = null)
{
eventHandler?.Invoke(sender, args);
}
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? eventName = null)
{
eventHandler?.Invoke(sender, args);
}
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? eventName = null)
{
eventHandler?.Invoke(sender, args);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Collections;
@@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.Events
public abstract class QueuingEventDispatcherBase : IEventDispatcher
{
//events will be enlisted in the order they are raised
private List<IEventDefinition> _events;
private List<IEventDefinition>? _events;
private readonly bool _raiseCancelable;
protected QueuingEventDispatcherBase(bool raiseCancelable)
@@ -30,7 +30,7 @@ namespace Umbraco.Cms.Core.Events
private List<IEventDefinition> Events => _events ?? (_events = new List<IEventDefinition>());
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string? eventName = null)
{
if (eventHandler == null) return args.Cancel;
if (_raiseCancelable == false) return args.Cancel;
@@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Events
return args.Cancel;
}
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
@@ -47,7 +47,7 @@ namespace Umbraco.Cms.Core.Events
return args.Cancel;
}
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
@@ -56,19 +56,19 @@ namespace Umbraco.Cms.Core.Events
return args.Cancel;
}
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string? eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition(eventHandler, sender, args, eventName));
}
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string? eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition<TArgs>(eventHandler, sender, args, eventName));
}
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string? eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition<TSender, TArgs>(eventHandler, sender, args, eventName));
@@ -106,8 +106,8 @@ namespace Umbraco.Cms.Core.Events
private class EventDefinitionInfos
{
public IEventDefinition EventDefinition { get; set; }
public Type[] SupersedeTypes { get; set; }
public IEventDefinition? EventDefinition { get; set; }
public Type[]? SupersedeTypes { get; set; }
}
// this is way too convoluted, the supersede attribute is used only on DeleteEventargs to specify
@@ -291,13 +291,13 @@ namespace Umbraco.Cms.Core.Events
private static bool IsSuperceeded(IEntity entity, EventDefinitionInfos infos, List<Tuple<IEntity, EventDefinitionInfos>> entities)
{
//var argType = meta.EventArgsType;
var argType = infos.EventDefinition.Args.GetType();
var argType = infos.EventDefinition?.Args.GetType();
// look for other instances of the same entity, coming from an event args that supersedes other event args,
// ie is marked with the attribute, and is not this event args (cannot supersede itself)
var superceeding = entities
.Where(x => x.Item2.SupersedeTypes.Length > 0 // has the attribute
&& x.Item2.EventDefinition.Args.GetType() != argType // is not the same
.Where(x => x.Item2.SupersedeTypes?.Length > 0 // has the attribute
&& x.Item2.EventDefinition?.Args.GetType() != argType // is not the same
&& Equals(x.Item1, entity)) // same entity
.ToArray();
@@ -306,27 +306,27 @@ namespace Umbraco.Cms.Core.Events
return false;
// delete event args does NOT supersedes 'unpublished' event
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "Unpublished")
if ((argType?.IsGenericType ?? false) && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition?.EventName == "Unpublished")
return false;
// found occurrences, need to determine if this event args is superseded
if (argType.IsGenericType)
if (argType?.IsGenericType ?? false)
{
// generic, must compare type arguments
var supercededBy = superceeding.FirstOrDefault(x =>
x.Item2.SupersedeTypes.Any(y =>
x.Item2.SupersedeTypes?.Any(y =>
// superseding a generic type which has the same generic type definition
// (but ... no matter the generic type parameters? could be different?)
y.IsGenericTypeDefinition && y == argType.GetGenericTypeDefinition()
// or superceeding a non-generic type which is ... (but... how is this ever possible? argType *is* generic?
|| y.IsGenericTypeDefinition == false && y == argType));
|| y.IsGenericTypeDefinition == false && y == argType) ?? false);
return supercededBy != null;
}
else
{
// non-generic, can compare types 1:1
var supercededBy = superceeding.FirstOrDefault(x =>
x.Item2.SupersedeTypes.Any(y => y == argType));
x.Item2.SupersedeTypes?.Any(y => y == argType) ?? false);
return supercededBy != null;
}
}

View File

@@ -75,18 +75,6 @@ namespace Umbraco.Extensions
yield return result;
}
/// <summary>The legacy distinct by.</summary>
/// <param name="source">The source.</param>
/// <param name="keySelector">The key selector.</param>
/// <typeparam name="TSource">Source type</typeparam>
/// <typeparam name="TKey">Key type</typeparam>
/// <returns>the unique list</returns>
public static IEnumerable<TSource> LegacyDistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource?, TKey> keySelector)
where TKey : IEquatable<TKey>
{
return source.Distinct(DelegateEqualityComparer<TSource>.CompareMember(keySelector));
}
/// <summary>
/// Returns a sequence of length <paramref name="count"/> whose elements are the result of invoking <paramref name="factory"/>.
/// </summary>

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Extensions
/// </summary>
public static class HostEnvironmentExtensions
{
private static string s_temporaryApplicationId;
private static string? s_temporaryApplicationId;
/// <summary>
/// Maps a virtual path to a physical path to the application's content root.

View File

@@ -365,7 +365,7 @@ namespace Umbraco.Extensions
/// returns <see langword="false"/>.</returns>
public static bool IsNullOrWhiteSpace(this string? value) => string.IsNullOrWhiteSpace(value);
public static string? IfNullOrWhiteSpace(this string str, string? defaultValue)
public static string? IfNullOrWhiteSpace(this string? str, string? defaultValue)
{
return str.IsNullOrWhiteSpace() ? defaultValue : str;
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Cms.Core.Mapping
@@ -121,7 +121,7 @@ namespace Umbraco.Cms.Core.Mapping
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
{
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
return source.Select(Map<TSourceElement, TTargetElement>).Where(x => x is not null).ToList()!;
}
#endregion

View File

@@ -1,4 +1,3 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
@@ -12,10 +11,9 @@ namespace Umbraco.Cms.Core.Models.ContentEditing
[DataMember(Name = "culture", IsRequired = true)]
[Required(AllowEmptyStrings = false)]
public string? IsoCode { get; set; }
public string IsoCode { get; set; } = null!;
[DataMember(Name = "name")]
[ReadOnly(true)]
public string? Name { get; set; }
[DataMember(Name = "isDefault")]

View File

@@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
using System.Runtime.Serialization;
using Umbraco.Cms.Core.Models.Entities;
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Core.Models
/// Gets or sets the culture name of the language.
/// </summary>
[DataMember]
string? CultureName { get; set; }
string CultureName { get; set; }
/// <summary>
/// Gets the <see cref="CultureInfo"/> object for the language.

View File

@@ -1,7 +1,5 @@
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Threading;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models.Entities;
@@ -14,18 +12,28 @@ namespace Umbraco.Cms.Core.Models
[DataContract(IsReference = true)]
public class Language : EntityBase, ILanguage
{
private readonly GlobalSettings _globalSettings;
private string _isoCode = null!;
private string? _cultureName;
private string _isoCode;
private string _cultureName;
private bool _isDefaultVariantLanguage;
private bool _mandatory;
private int? _fallbackLanguageId;
/// <summary>
/// Initializes a new instance of the <see cref="Language" /> class.
/// </summary>
/// <param name="isoCode">The ISO code of the language.</param>
/// <param name="cultureName">The name of the language.</param>
public Language(string isoCode, string cultureName)
{
_isoCode = isoCode ?? throw new ArgumentNullException(nameof(isoCode));
_cultureName = cultureName ?? throw new ArgumentNullException(nameof(cultureName));
}
[Obsolete("Use the constructor not requiring global settings and accepting an explicit name instead, scheduled for removal in V11.")]
public Language(GlobalSettings globalSettings, string isoCode)
{
IsoCode = isoCode;
_globalSettings = globalSettings;
_isoCode = isoCode ?? throw new ArgumentNullException(nameof(isoCode));
_cultureName = CultureInfo.GetCultureInfo(isoCode).EnglishName;
}
/// <inheritdoc />
@@ -33,64 +41,25 @@ namespace Umbraco.Cms.Core.Models
public string IsoCode
{
get => _isoCode;
set => SetPropertyValueAndDetectChanges(value, ref _isoCode!, nameof(IsoCode));
set
{
ArgumentNullException.ThrowIfNull(value);
SetPropertyValueAndDetectChanges(value, ref _isoCode!, nameof(IsoCode));
}
}
/// <inheritdoc />
[DataMember]
public string? CultureName
public string CultureName
{
// CultureInfo.DisplayName is the name in the installed .NET language
// .NativeName is the name in culture info's language
// .EnglishName is the name in English
//
// there is no easy way to get the name in a specified culture (which would need to be installed on the server)
// this works:
// var rm = new ResourceManager("mscorlib", typeof(int).Assembly);
// var name = rm.GetString("Globalization.ci_" + culture.Name, displayCulture);
// but can we rely on it?
//
// and... DisplayName is captured and cached in culture infos returned by GetCultureInfo(), using
// the value for the current thread culture at the moment it is first retrieved - whereas creating
// a new CultureInfo() creates a new instance, which _then_ can get DisplayName again in a different
// culture
//
// I assume that, on a site, all language names should be in the SAME language, in DB,
// and that would be the Umbraco.Core.DefaultUILanguage (app setting) - BUT if by accident
// ANY culture has been retrieved with another current thread culture - it's now corrupt
//
// so, the logic below ensures that the name always end up being the correct name
// see also LanguageController.GetAllCultures which is doing the same
//
// all this, including the ugly settings injection, because se store language names in db,
// otherwise it would be ok to simply return new CultureInfo(IsoCode).DisplayName to get the name
// in whatever culture is current - we should not do it, see task #3623
//
// but then, some tests that compare audit strings (for culture names) would need to be fixed
get
get => _cultureName;
set
{
if (_cultureName != null) return _cultureName;
ArgumentNullException.ThrowIfNull(value);
// capture
var threadUiCulture = Thread.CurrentThread.CurrentUICulture;
try
{
var defaultUiCulture = CultureInfo.GetCultureInfo(_globalSettings.DefaultUILanguage);
Thread.CurrentThread.CurrentUICulture = defaultUiCulture;
// get name - new-ing an instance to get proper display name
return new CultureInfo(IsoCode).DisplayName;
}
finally
{
// restore
Thread.CurrentThread.CurrentUICulture = threadUiCulture;
}
SetPropertyValueAndDetectChanges(value, ref _cultureName!, nameof(CultureName));
}
set => SetPropertyValueAndDetectChanges(value, ref _cultureName, nameof(CultureName));
}
/// <inheritdoc />

View File

@@ -84,7 +84,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
target.Translations.Add(new DictionaryTranslationDisplay
{
IsoCode = lang.IsoCode,
DisplayName = lang.CultureInfo?.DisplayName,
DisplayName = lang.CultureName,
Translation = translation?.Value ?? string.Empty,
LanguageId = lang.Id
});
@@ -106,7 +106,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
target.Translations.Add(
new DictionaryOverviewTranslationDisplay
{
DisplayName = lang.CultureInfo?.DisplayName,
DisplayName = lang.CultureName,
HasTranslation = translation != null && string.IsNullOrEmpty(translation.Value) == false
});
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Mapping;
@@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
{
target.Id = source.Id;
target.IsoCode = source.IsoCode;
target.Name = source.CultureInfo?.DisplayName;
target.Name = source.CultureName;
target.IsDefault = source.IsDefault;
target.IsMandatory = source.IsMandatory;
target.FallbackLanguageId = source.FallbackLanguageId;

View File

@@ -1,9 +1,7 @@
using System;
using System.Collections;
namespace Umbraco.Cms.Core.Models.PublishedContent
{
/// <summary>
/// Provides the published model creation service.
/// </summary>
@@ -13,23 +11,40 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
/// Creates a strongly-typed model representing a published element.
/// </summary>
/// <param name="element">The original published element.</param>
/// <returns>The strongly-typed model representing the published element, or the published element
/// itself it the factory has no model for the corresponding element type.</returns>
/// <returns>
/// The strongly-typed model representing the published element,
/// or the published element itself it the factory has no model for the corresponding element type.
/// </returns>
IPublishedElement CreateModel(IPublishedElement element);
/// <summary>
/// Creates a List{T} of a strongly-typed model for a model type alias.
/// </summary>
/// <param name="alias">The model type alias.</param>
/// <returns>A List{T} of the strongly-typed model, exposed as an IList.</returns>
/// <returns>
/// A List{T} of the strongly-typed model, exposed as an IList.
/// </returns>
IList? CreateModelList(string? alias);
/// <summary>
/// Gets the Type of a strongly-typed model for a model type alias.
/// </summary>
/// <param name="alias">The model type alias.</param>
/// <returns>
/// The type of the strongly-typed model.
/// </returns>
Type GetModelType(string? alias);
/// <summary>
/// Maps a CLR type that may contain model types, to an actual CLR type.
/// </summary>
/// <param name="type">The CLR type.</param>
/// <returns>The actual CLR type.</returns>
/// <remarks>See <seealso cref="ModelType"/> for more details.</remarks>
/// <returns>
/// The actual CLR type.
/// </returns>
/// <remarks>
/// See <seealso cref="ModelType" /> for more details.
/// </remarks>
Type MapModelType(Type type);
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Umbraco.Cms.Core.Models.PublishedContent
{
@@ -14,6 +12,9 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
/// <inheritdoc />
public IList CreateModelList(string? alias) => new List<IPublishedElement>();
/// <inheritdoc />
public Type GetModelType(string? alias) => typeof(IPublishedElement);
/// <inheritdoc />
public Type MapModelType(Type type) => typeof(IPublishedElement);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.PropertyEditors;
@@ -84,7 +84,7 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
if (_publishedDataTypes == null)
{
var dataTypes = _dataTypeService.GetAll();
_publishedDataTypes = dataTypes?.ToDictionary(x => x.Id, CreatePublishedDataType);
_publishedDataTypes = dataTypes.ToDictionary(x => x.Id, CreatePublishedDataType);
}
publishedDataTypes = _publishedDataTypes;
@@ -104,7 +104,7 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
if (_publishedDataTypes == null)
{
var dataTypes = _dataTypeService.GetAll();
_publishedDataTypes = dataTypes?.ToDictionary(x => x.Id, CreatePublishedDataType);
_publishedDataTypes = dataTypes.ToDictionary(x => x.Id, CreatePublishedDataType);
}
else
{
@@ -112,11 +112,8 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
_publishedDataTypes.Remove(id);
var dataTypes = _dataTypeService.GetAll(ids);
if (dataTypes is not null)
{
foreach (var dataType in dataTypes)
_publishedDataTypes[dataType.Id] = CreatePublishedDataType(dataType);
}
foreach (var dataType in dataTypes)
_publishedDataTypes[dataType.Id] = CreatePublishedDataType(dataType);
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace Umbraco.Cms.Core.Models.PublishedContent
@@ -59,20 +57,27 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
if (parms.Length == 2 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType) && typeof(IPublishedValueFallback).IsAssignableFrom(parms[1].ParameterType))
{
if (constructor != null)
{
throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPublishedElement.");
}
constructor = ctor;
parameterType = parms[0].ParameterType;
}
}
if (constructor == null)
{
throw new InvalidOperationException($"Type {type.FullName} is missing a public constructor with one argument of type, or implementing, IPublishedElement.");
}
var attribute = type.GetCustomAttribute<PublishedModelAttribute>(false);
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
if (modelInfos.TryGetValue(typeName, out var modelInfo))
{
throw new InvalidOperationException($"Both types '{type.AssemblyQualifiedName}' and '{modelInfo.ModelType?.AssemblyQualifiedName}' want to be a model type for content type with alias \"{typeName}\".");
}
// have to use an unsafe ctor because we don't know the types, really
var modelCtor = ReflectionUtilities.EmitConstructorUnsafe<Func<object, IPublishedValueFallback, object>>(constructor);
@@ -89,15 +94,16 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
public IPublishedElement CreateModel(IPublishedElement element)
{
// fail fast
if (_modelInfos == null)
return element;
if (element.ContentType.Alias is null || !_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo))
if (_modelInfos is null || element.ContentType.Alias is null || !_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo))
{
return element;
}
// ReSharper disable once UseMethodIsInstanceOfType
if (modelInfo.ParameterType?.IsAssignableFrom(element.GetType()) == false)
{
throw new InvalidOperationException($"Model {modelInfo.ModelType} expects argument of type {modelInfo.ParameterType.FullName}, but got {element.GetType().FullName}.");
}
// can cast, because we checked when creating the ctor
return (IPublishedElement)modelInfo.Ctor!(element, _publishedValueFallback);
@@ -107,21 +113,42 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
public IList? CreateModelList(string? alias)
{
// fail fast
if (_modelInfos == null)
return new List<IPublishedElement>();
if (alias is null || !_modelInfos.TryGetValue(alias, out var modelInfo) || modelInfo.ModelType is null)
if (_modelInfos is null || alias is null || !_modelInfos.TryGetValue(alias, out var modelInfo) || modelInfo.ModelType is null)
{
return new List<IPublishedElement>();
}
var ctor = modelInfo.ListCtor;
if (ctor != null) return ctor();
if (ctor != null)
{
return ctor();
}
var listType = typeof(List<>).MakeGenericType(modelInfo.ModelType);
ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor<Func<IList>>(declaring: listType);
if(ctor is not null) return ctor();
if (ctor is not null)
{
return ctor();
}
return null;
}
/// <inheritdoc />
public Type GetModelType(string? alias)
{
// fail fast
if (_modelInfos is null ||
alias is null ||
!_modelInfos.TryGetValue(alias, out var modelInfo) ||
modelInfo.ModelType is null)
{
return typeof(IPublishedElement);
}
return modelInfo.ModelType;
}
/// <inheritdoc />
public Type MapModelType(Type type)
=> ModelType.Map(type, _modelTypeMap);

View File

@@ -4,6 +4,6 @@ namespace Umbraco.Cms.Core.Notifications
{
public interface IStatefulNotification : INotification
{
IDictionary<string, object> State { get; set; }
IDictionary<string, object?> State { get; set; }
}
}

View File

@@ -4,7 +4,7 @@ namespace Umbraco.Cms.Core.Notifications
{
public static class NotificationExtensions
{
public static T WithState<T>(this T notification, IDictionary<string, object>? state) where T : IStatefulNotification
public static T WithState<T>(this T notification, IDictionary<string, object?>? state) where T : IStatefulNotification
{
notification.State = state!;
return notification;

View File

@@ -6,15 +6,15 @@ namespace Umbraco.Cms.Core.Notifications
{
public abstract class StatefulNotification : IStatefulNotification
{
private IDictionary<string, object>? _state;
private IDictionary<string, object?>? _state;
/// <summary>
/// This can be used by event subscribers to store state in the notification so they easily deal with custom state data between
/// a starting ("ing") and an ending ("ed") notification
/// </summary>
public IDictionary<string, object> State
public IDictionary<string, object?> State
{
get => _state ??= new Dictionary<string, object>();
get => _state ??= new Dictionary<string, object?>();
set => _state = value;
}
}

View File

@@ -577,7 +577,7 @@ namespace Umbraco.Cms.Core.Packaging
////Now, we have all property Ids/Aliases and their referenced document Ids and tags
//var allExportedTaggedEntities = allTaggedEntities.Where(x => allExportedIds.Contains(x.EntityId))
// .LegacyDistinctBy(x => x.EntityId)
// .DistinctBy(x => x.EntityId)
// .OrderBy(x => x.EntityId);
//foreach (var taggedEntity in allExportedTaggedEntities)

View File

@@ -2,11 +2,13 @@
// See LICENSE for more details.
using System;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Core.PropertyEditors
{
@@ -27,7 +29,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
[Obsolete("Please use constructor that takes an IEditorConfigurationParser instead")]
public LabelPropertyEditor(IDataValueEditorFactory dataValueEditorFactory,
IIOHelper ioHelper)
: base(dataValueEditorFactory)
: this(dataValueEditorFactory, ioHelper, StaticServiceProvider.Instance.GetRequiredService<IEditorConfigurationParser>())
{
}

View File

@@ -20,6 +20,7 @@ namespace Umbraco.Cms.Core.PublishedCache.Internal
Version = Guid.Empty;
Path = string.Empty;
ContentType = contentType;
Properties = Enumerable.Empty<IPublishedProperty>();
}
private Dictionary<string, PublishedCultureInfo>? _cultures;

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
@@ -33,55 +29,16 @@ namespace Umbraco.Extensions
UriUtility uriUtility,
IPublishedUrlProvider publishedUrlProvider)
{
if (content == null)
{
throw new ArgumentNullException(nameof(content));
}
if (publishedRouter == null)
{
throw new ArgumentNullException(nameof(publishedRouter));
}
if (umbracoContext == null)
{
throw new ArgumentNullException(nameof(umbracoContext));
}
if (localizationService == null)
{
throw new ArgumentNullException(nameof(localizationService));
}
if (textService == null)
{
throw new ArgumentNullException(nameof(textService));
}
if (contentService == null)
{
throw new ArgumentNullException(nameof(contentService));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
if (publishedUrlProvider == null)
{
throw new ArgumentNullException(nameof(publishedUrlProvider));
}
if (uriUtility == null)
{
throw new ArgumentNullException(nameof(uriUtility));
}
if (variationContextAccessor == null)
{
throw new ArgumentNullException(nameof(variationContextAccessor));
}
ArgumentNullException.ThrowIfNull(content);
ArgumentNullException.ThrowIfNull(publishedRouter);
ArgumentNullException.ThrowIfNull(umbracoContext);
ArgumentNullException.ThrowIfNull(localizationService);
ArgumentNullException.ThrowIfNull(textService);
ArgumentNullException.ThrowIfNull(contentService);
ArgumentNullException.ThrowIfNull(variationContextAccessor);
ArgumentNullException.ThrowIfNull(logger);
ArgumentNullException.ThrowIfNull(uriUtility);
ArgumentNullException.ThrowIfNull(publishedUrlProvider);
var result = new List<UrlInfo>();
@@ -107,9 +64,7 @@ namespace Umbraco.Extensions
// get all URLs for all cultures
// in a HashSet, so de-duplicates too
foreach (UrlInfo cultureUrl in await GetContentUrlsByCultureAsync(content, cultures, publishedRouter,
umbracoContext, contentService, textService, variationContextAccessor, logger, uriUtility,
publishedUrlProvider))
foreach (UrlInfo cultureUrl in await GetContentUrlsByCultureAsync(content, cultures, publishedRouter, umbracoContext, contentService, textService, variationContextAccessor, logger, uriUtility, publishedUrlProvider))
{
urls.Add(cultureUrl);
}
@@ -120,25 +75,19 @@ namespace Umbraco.Extensions
// in some cases there will be the same URL for multiple cultures:
// * The entire branch is invariant
// * If there are less domain/cultures assigned to the branch than the number of cultures/languages installed
if (urlGroup.Key)
{
result.AddRange(urlGroup.LegacyDistinctBy(x => x!.Text.ToUpperInvariant())
.OrderBy(x => x.Text).ThenBy(x => x.Culture));
result.AddRange(urlGroup.DistinctBy(x => x.Text, StringComparer.OrdinalIgnoreCase).OrderBy(x => x.Text).ThenBy(x => x.Culture));
}
else
{
result.AddRange(urlGroup);
}
}
// get the 'other' URLs - ie not what you'd get with GetUrl() but URLs that would route to the document, nevertheless.
// for these 'other' URLs, we don't check whether they are routable, collide, anything - we just report them.
foreach (UrlInfo otherUrl in publishedUrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text)
.ThenBy(x => x.Culture))
foreach (UrlInfo otherUrl in publishedUrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text).ThenBy(x => x.Culture))
{
// avoid duplicates
if (urls.Add(otherUrl))
@@ -202,8 +151,7 @@ namespace Umbraco.Extensions
// got a URL, deal with collisions, add URL
default:
// detect collisions, etc
Attempt<UrlInfo?> hasCollision = await DetectCollisionAsync(logger, content, url, culture,
umbracoContext, publishedRouter, textService, variationContextAccessor, uriUtility);
Attempt<UrlInfo?> hasCollision = await DetectCollisionAsync(logger, content, url, culture, umbracoContext, publishedRouter, textService, variationContextAccessor, uriUtility);
if (hasCollision.Success && hasCollision.Result is not null)
{
result.Add(hasCollision.Result);
@@ -220,8 +168,7 @@ namespace Umbraco.Extensions
return result;
}
private static UrlInfo HandleCouldNotGetUrl(IContent content, string culture, IContentService contentService,
ILocalizedTextService textService)
private static UrlInfo HandleCouldNotGetUrl(IContent content, string culture, IContentService contentService, ILocalizedTextService textService)
{
// document has a published version yet its URL is "#" => a parent must be
// unpublished, walk up the tree until we find it, and report.
@@ -229,8 +176,8 @@ namespace Umbraco.Extensions
do
{
parent = parent.ParentId > 0 ? contentService.GetParent(parent) : null;
} while (parent != null && parent.Published &&
(!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture)));
}
while (parent != null && parent.Published && (!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture)));
if (parent == null)
{
@@ -241,18 +188,22 @@ namespace Umbraco.Extensions
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);
}
// 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);
}
private static async Task<Attempt<UrlInfo?>> DetectCollisionAsync(ILogger logger, IContent content, string url,
string culture, IUmbracoContext umbracoContext, IPublishedRouter publishedRouter,
ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor,
private static async Task<Attempt<UrlInfo?>> DetectCollisionAsync(
ILogger logger,
IContent content,
string url,
string culture,
IUmbracoContext umbracoContext,
IPublishedRouter publishedRouter,
ILocalizedTextService textService,
IVariationContextAccessor variationContextAccessor,
UriUtility uriUtility)
{
// test for collisions on the 'main' URL
@@ -264,14 +215,11 @@ namespace Umbraco.Extensions
uri = uriUtility.UriToUmbraco(uri);
IPublishedRequestBuilder builder = await publishedRouter.CreateRequestAsync(uri);
IPublishedRequest pcr =
await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound));
IPublishedRequest pcr = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound));
if (!pcr.HasPublishedContent())
{
const string logMsg = nameof(DetectCollisionAsync) +
" did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}";
const string logMsg = nameof(DetectCollisionAsync) + " did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}";
logger.LogDebug(logMsg, url, uri, culture);
var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture);

View File

@@ -1,7 +1,9 @@
using System;
using System.Net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Core.Services.Implement
{
@@ -13,6 +15,7 @@ namespace Umbraco.Cms.Core.Services.Implement
// Scheduled for removal in v12
[Obsolete("Please use the contructor that takes an IIpadressUtilities instead")]
public BasicAuthService(IOptionsMonitor<BasicAuthSettings> optionsMonitor)
: this(optionsMonitor, StaticServiceProvider.Instance.GetRequiredService<IIpAddressUtilities>())
{
_basicAuthSettings = optionsMonitor.CurrentValue;

View File

@@ -1377,7 +1377,7 @@ namespace Umbraco.Cms.Core.Services
/// </remarks>
private PublishResult CommitDocumentChangesInternal(ICoreScope scope, IContent content,
EventMessages eventMessages, IReadOnlyCollection<ILanguage> allLangs,
IDictionary<string, object>? notificationState,
IDictionary<string, object?>? notificationState,
int userId = Constants.Security.SuperUserId,
bool branchOne = false, bool branchRoot = false)
{
@@ -3036,7 +3036,7 @@ namespace Umbraco.Cms.Core.Services
private PublishResult StrategyCanPublish(ICoreScope scope, IContent content, bool checkPath,
IReadOnlyList<string>? culturesPublishing,
IReadOnlyCollection<string>? culturesUnpublishing, EventMessages evtMsgs,
IReadOnlyCollection<ILanguage> allLangs, IDictionary<string, object>? notificationState)
IReadOnlyCollection<ILanguage> allLangs, IDictionary<string, object?>? notificationState)
{
// raise Publishing notification
if (scope.Notifications.PublishCancelable(

View File

@@ -304,7 +304,7 @@ namespace Umbraco.Cms.Core.Services
return Enumerable.Empty<TItem>();
}
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
{
scope.ReadLock(ReadLockIds);
@@ -623,7 +623,7 @@ namespace Umbraco.Cms.Core.Services
scope.Notifications.Publish(GetContentTypeChangedNotification(changes, eventMessages));
DeletedNotification<TItem> deletedNotification = GetDeletedNotification(deleted.LegacyDistinctBy(x => x!.Id), eventMessages);
DeletedNotification<TItem> deletedNotification = GetDeletedNotification(deleted.DistinctBy(x => x.Id), eventMessages);
deletedNotification.WithStateFrom(deletingNotification);
scope.Notifications.Publish(deletedNotification);
@@ -649,9 +649,7 @@ namespace Umbraco.Cms.Core.Services
scope.WriteLock(WriteLockIds);
// all descendants are going to be deleted
TItem[] allDescendantsAndSelf = itemsA.SelectMany(xx => GetDescendants(xx.Id, true))
.LegacyDistinctBy(x => x!.Id)
.ToArray();
TItem[] allDescendantsAndSelf = itemsA.SelectMany(xx => GetDescendants(xx.Id, true)).DistinctBy(x => x.Id).ToArray();
TItem[] deleted = allDescendantsAndSelf;
// all impacted (through composition) probably lose some properties
@@ -681,7 +679,7 @@ namespace Umbraco.Cms.Core.Services
scope.Notifications.Publish(GetContentTypeChangedNotification(changes, eventMessages));
DeletedNotification<TItem> deletedNotification = GetDeletedNotification(deleted.LegacyDistinctBy(x => x!.Id), eventMessages);
DeletedNotification<TItem> deletedNotification = GetDeletedNotification(deleted.DistinctBy(x => x.Id), eventMessages);
deletedNotification.WithStateFrom(deletingNotification);
scope.Notifications.Publish(deletedNotification);

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Exceptions;
@@ -12,6 +13,7 @@ using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Services.Implement
@@ -32,7 +34,9 @@ namespace Umbraco.Cms.Core.Services.Implement
private readonly ILocalizationService _localizationService;
private readonly IShortStringHelper _shortStringHelper;
private readonly IJsonSerializer _jsonSerializer;
private readonly IEditorConfigurationParser _editorConfigurationParser;
[Obsolete("Please use constructor that takes an ")]
public DataTypeService(
IDataValueEditorFactory dataValueEditorFactory,
ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory,
@@ -41,6 +45,45 @@ namespace Umbraco.Cms.Core.Services.Implement
IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer)
: this(
dataValueEditorFactory,
provider,
loggerFactory,
eventMessagesFactory,
dataTypeRepository,
dataTypeContainerRepository,
auditRepository,
entityRepository,
contentTypeRepository,
ioHelper,
localizedTextService,
localizationService,
shortStringHelper,
jsonSerializer,
StaticServiceProvider.Instance.GetRequiredService<IEditorConfigurationParser>())
{
_dataValueEditorFactory = dataValueEditorFactory;
_dataTypeRepository = dataTypeRepository;
_dataTypeContainerRepository = dataTypeContainerRepository;
_auditRepository = auditRepository;
_entityRepository = entityRepository;
_contentTypeRepository = contentTypeRepository;
_ioHelper = ioHelper;
_localizedTextService = localizedTextService;
_localizationService = localizationService;
_shortStringHelper = shortStringHelper;
_jsonSerializer = jsonSerializer;
}
public DataTypeService(
IDataValueEditorFactory dataValueEditorFactory,
ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory,
IDataTypeRepository dataTypeRepository, IDataTypeContainerRepository dataTypeContainerRepository,
IAuditRepository auditRepository, IEntityRepository entityRepository, IContentTypeRepository contentTypeRepository,
IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IEditorConfigurationParser editorConfigurationParser)
: base(provider, loggerFactory, eventMessagesFactory)
{
_dataValueEditorFactory = dataValueEditorFactory;
@@ -54,6 +97,7 @@ namespace Umbraco.Cms.Core.Services.Implement
_localizationService = localizationService;
_shortStringHelper = shortStringHelper;
_jsonSerializer = jsonSerializer;
_editorConfigurationParser = editorConfigurationParser;
}
#region Containers
@@ -320,15 +364,11 @@ namespace Umbraco.Cms.Core.Services.Implement
/// </summary>
/// <param name="ids">Optional array of Ids</param>
/// <returns>An enumerable list of <see cref="IDataType"/> objects</returns>
public IEnumerable<IDataType>? GetAll(params int[] ids)
public IEnumerable<IDataType> GetAll(params int[] ids)
{
using (var scope = ScopeProvider.CreateCoreScope(autoComplete: true))
{
var dataTypes = _dataTypeRepository.GetMany(ids);
if (dataTypes is null)
{
return null;
}
ConvertMissingEditorsOfDataTypesToLabels(dataTypes);
return dataTypes;
@@ -353,7 +393,7 @@ namespace Umbraco.Cms.Core.Services.Implement
.Where(x => x.Editor is MissingPropertyEditor);
foreach (var dataType in dataTypesWithMissingEditors)
{
dataType.Editor = new LabelPropertyEditor(_dataValueEditorFactory, _ioHelper);
dataType.Editor = new LabelPropertyEditor(_dataValueEditorFactory, _ioHelper, _editorConfigurationParser);
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
@@ -642,9 +643,12 @@ namespace Umbraco.Cms.Core.Services
public IEnumerable<string> GetPartialViewSnippetNames(params string[] filterNames)
{
var snippetPath = _hostingEnvironment.MapPathContentRoot($"{Constants.SystemDirectories.Umbraco}/PartialViewMacros/Templates/");
var files = Directory.GetFiles(snippetPath, "*.cshtml")
.Select(Path.GetFileNameWithoutExtension)
var snippetProvider =
new EmbeddedFileProvider(this.GetType().Assembly, "Umbraco.Cms.Core.EmbeddedResources.Snippets");
var files = snippetProvider.GetDirectoryContents(string.Empty)
.Where(x => !x.IsDirectory && x.Name.EndsWith(".cshtml"))
.Select(x => Path.GetFileNameWithoutExtension(x.Name))
.Except(filterNames, StringComparer.InvariantCultureIgnoreCase)
.ToArray();
@@ -977,14 +981,18 @@ namespace Umbraco.Cms.Core.Services
throw new ArgumentOutOfRangeException(nameof(partialViewType));
}
var snippetProvider =
new EmbeddedFileProvider(this.GetType().Assembly, "Umbraco.Cms.Core.EmbeddedResources.Snippets");
var file = snippetProvider.GetDirectoryContents(string.Empty).FirstOrDefault(x=>x.Exists && x.Name.Equals(snippetName + ".cshtml"));
// Try and get the snippet path
Attempt<string> snippetPathAttempt = TryGetSnippetPath(snippetName);
if (snippetPathAttempt.Success == false)
if (file is null)
{
throw new InvalidOperationException("Could not load snippet with name " + snippetName);
}
using (var snippetFile = new StreamReader(System.IO.File.OpenRead(snippetPathAttempt.Result!)))
using (var snippetFile = new StreamReader(file.CreateReadStream()))
{
var snippetContent = snippetFile.ReadToEnd().Trim();

View File

@@ -53,7 +53,7 @@ namespace Umbraco.Cms.Core.Services
/// </summary>
/// <param name="ids">Optional array of Ids</param>
/// <returns>An enumerable list of <see cref="IDataType"/> objects</returns>
IEnumerable<IDataType>? GetAll(params int[] ids);
IEnumerable<IDataType> GetAll(params int[] ids);
/// <summary>
/// Saves an <see cref="IDataType"/>

View File

@@ -5,6 +5,8 @@ using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Internal;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Extensions;
@@ -17,6 +19,7 @@ namespace Umbraco.Cms.Core.Services
public class LocalizedTextServiceFileSources
{
private readonly ILogger<LocalizedTextServiceFileSources> _logger;
private readonly IDirectoryContents _directoryContents;
private readonly IAppPolicyCache _cache;
private readonly IEnumerable<LocalizedTextServiceSupplementaryFileSource>? _supplementFileSources;
private readonly DirectoryInfo? _fileSourceFolder;
@@ -26,6 +29,21 @@ namespace Umbraco.Cms.Core.Services
private readonly Lazy<Dictionary<CultureInfo, Lazy<XDocument>>> _xmlSources;
[Obsolete("Use ctor with all params. This will be removed in Umbraco 12")]
public LocalizedTextServiceFileSources(
ILogger<LocalizedTextServiceFileSources> logger,
AppCaches appCaches,
DirectoryInfo fileSourceFolder,
IEnumerable<LocalizedTextServiceSupplementaryFileSource> supplementFileSources)
:this(
logger,
appCaches,
fileSourceFolder,
supplementFileSources, new NotFoundDirectoryContents())
{
}
/// <summary>
/// This is used to configure the file sources with the main file sources shipped with Umbraco and also including supplemental/plugin based
/// localization files. The supplemental files will be loaded in and merged in after the primary files.
@@ -39,36 +57,37 @@ namespace Umbraco.Cms.Core.Services
ILogger<LocalizedTextServiceFileSources> logger,
AppCaches appCaches,
DirectoryInfo fileSourceFolder,
IEnumerable<LocalizedTextServiceSupplementaryFileSource> supplementFileSources)
IEnumerable<LocalizedTextServiceSupplementaryFileSource> supplementFileSources,
IDirectoryContents directoryContents
)
{
if (logger == null) throw new ArgumentNullException("logger");
if (appCaches == null) throw new ArgumentNullException("cache");
if (fileSourceFolder == null) throw new ArgumentNullException("fileSourceFolder");
_logger = logger;
_directoryContents = directoryContents;
_cache = appCaches.RuntimeCache;
if (fileSourceFolder.Exists == false)
{
_logger.LogWarning("The folder does not exist: {FileSourceFolder}, therefore no sources will be discovered", fileSourceFolder.FullName);
}
else
{
_fileSourceFolder = fileSourceFolder;
_supplementFileSources = supplementFileSources;
}
_fileSourceFolder = fileSourceFolder;
_supplementFileSources = supplementFileSources;
//Create the lazy source for the _xmlSources
_xmlSources = new Lazy<Dictionary<CultureInfo, Lazy<XDocument>>>(() =>
{
var result = new Dictionary<CultureInfo, Lazy<XDocument>>();
if (_fileSourceFolder == null) return result;
foreach (var fileInfo in _fileSourceFolder.GetFiles("*.xml"))
var files = GetLanguageFiles();
if (!files.Any())
{
return result;
}
foreach (var fileInfo in files)
{
var localCopy = fileInfo;
var filename = Path.GetFileNameWithoutExtension(localCopy.FullName).Replace("_", "-");
var filename = Path.GetFileNameWithoutExtension(localCopy.Name).Replace("_", "-");
// TODO: Fix this nonsense... would have to wait until v8 to store the language files with their correct
// names instead of storing them as 2 letters but actually having a 4 letter culture. So now, we
@@ -80,7 +99,7 @@ namespace Umbraco.Cms.Core.Services
{
//we need to open the file to see if we can read it's 'real' culture, we'll use XmlReader since we don't
//want to load in the entire doc into mem just to read a single value
using (var fs = fileInfo.OpenRead())
using (var fs = fileInfo.CreateReadStream())
using (var reader = XmlReader.Create(fs))
{
if (reader.IsStartElement())
@@ -98,7 +117,7 @@ namespace Umbraco.Cms.Core.Services
}
catch (CultureNotFoundException)
{
_logger.LogWarning("The culture {CultureValue} found in the file {CultureFile} is not a valid culture", cultureVal, fileInfo.FullName);
_logger.LogWarning("The culture {CultureValue} found in the file {CultureFile} is not a valid culture", cultureVal, fileInfo.Name);
//If the culture in the file is invalid, we'll just hope the file name is a valid culture below, otherwise
// an exception will be thrown.
}
@@ -119,7 +138,7 @@ namespace Umbraco.Cms.Core.Services
XDocument xdoc;
//load in primary
using (var fs = localCopy.OpenRead())
using (var fs = localCopy.CreateReadStream())
{
xdoc = XDocument.Load(fs);
}
@@ -128,7 +147,7 @@ namespace Umbraco.Cms.Core.Services
MergeSupplementaryFiles(culture, xdoc);
return xdoc;
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] { localCopy.FullName })!);
}, isSliding: true, timeout: TimeSpan.FromMinutes(10))!);
}
return result;
});
@@ -136,6 +155,30 @@ namespace Umbraco.Cms.Core.Services
}
private IEnumerable<IFileInfo> GetLanguageFiles()
{
var result = new List<IFileInfo>();
if (_fileSourceFolder is not null && _fileSourceFolder.Exists)
{
result.AddRange(
new PhysicalDirectoryContents(_fileSourceFolder.FullName)
.Where(x => !x.IsDirectory && x.Name.EndsWith(".xml"))
);
}
if (_directoryContents.Exists)
{
result.AddRange(
_directoryContents
.Where(x => !x.IsDirectory && x.Name.EndsWith(".xml"))
);
}
return result;
}
/// <summary>
/// Constructor
/// </summary>

Some files were not shown because too many files have changed in this diff Show More