Compare commits

...
Author SHA1 Message Date
Niels LyngsøandGitHub 1486121ffa V17/hotfix/revert parts of 21982 (#22656)
* do not inherit property write permissions

* revert hidding edit actions
2026-04-30 12:49:10 +02:00
Niels Lyngsø 0908586e89 update package-lock with version number 2026-04-30 10:21:29 +02:00
Andy Butland e6f53b9d30 Bump version to 17.3.5. 2026-04-30 10:14:57 +02:00
Andy Butland 87e12b9ee2 Migrations: Fix RetrustForeignKeyAndCheckConstraints failing when data violates a constraint (#22488)
* Fix exception handling in RetrustForeignKeyAndCheckConstraints migration step.

* Addressed code review feedback.
2026-04-16 07:20:38 +02:00
Andy Butland 6ad2a17c09 Bumped version to 17.3.4. 2026-04-16 07:20:09 +02:00
12 changed files with 34 additions and 35 deletions
@@ -1,6 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Infrastructure.Persistence;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_17_3_0;
@@ -12,15 +14,28 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_17_3_0;
/// </summary>
public class RetrustForeignKeyAndCheckConstraints : AsyncMigrationBase
{
private readonly IUmbracoDatabaseFactory _databaseFactory;
/// <summary>
/// Initializes a new instance of the <see cref="RetrustForeignKeyAndCheckConstraints"/> class.
/// </summary>
/// <param name="context">The migration context.</param>
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 18.")]
public RetrustForeignKeyAndCheckConstraints(IMigrationContext context)
: base(context)
: this(
context,
StaticServiceProvider.Instance.GetRequiredService<IUmbracoDatabaseFactory>())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RetrustForeignKeyAndCheckConstraints"/> class.
/// </summary>
/// <param name="context">The migration context.</param>
/// <param name="databaseFactory">The database factory used to create separate connections for constraint validation.</param>
public RetrustForeignKeyAndCheckConstraints(IMigrationContext context, IUmbracoDatabaseFactory databaseFactory)
: base(context) => _databaseFactory = databaseFactory;
/// <inheritdoc />
protected override Task MigrateAsync()
{
@@ -67,17 +82,21 @@ public class RetrustForeignKeyAndCheckConstraints : AsyncMigrationBase
Logger.LogInformation("Found {Count} untrusted constraint(s) to re-trust.", untrustedConstraints.Count);
// Ensure we have a long command timeout, in case the migration targets a huge table.
EnsureLongCommandTimeout(Database);
// ALTER TABLE ... WITH CHECK CHECK CONSTRAINT is executed on a separate database connection
// to isolate failures from the migration scope's transaction. When constraint validation fails
// (e.g. orphaned FK rows), the error can zombie the .NET SqlTransaction even when caught by
// T-SQL TRY...CATCH, because the transaction state change propagates through the TDS (Tabular
// Data Stream) protocol layer that underlies SQL Server client-server communication.
// Using a separate connection (which has no explicit transaction) avoids this entirely —
// TRY...CATCH works correctly and no SqlException is thrown to the .NET layer.
var retrusted = 0;
var failed = 0;
using IUmbracoDatabase db = _databaseFactory.CreateDatabase();
EnsureLongCommandTimeout(db);
foreach (UntrustedConstraintDto constraint in untrustedConstraints)
{
// Use T-SQL TRY...CATCH to handle errors at the SQL level. This prevents a constraint
// validation failure from dooming the .NET SqlTransaction, which would cause all
// subsequent operations to fail with "This SqlTransaction has completed".
// Leading semicolon prevents NPoco's auto-select from prepending
// "SELECT ... FROM []" based on the empty [TableName("")] attribute.
var sql = $@";
@@ -89,7 +108,7 @@ BEGIN CATCH
SELECT CAST(0 AS BIT) AS Success, ERROR_MESSAGE() AS ErrorMessage;
END CATCH";
RetrustResultDto result = Database.Single<RetrustResultDto>(sql);
RetrustResultDto result = db.Single<RetrustResultDto>(sql);
if (result.Success)
{
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@umbraco-cms/backoffice",
"version": "17.3.3",
"version": "17.3.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@umbraco-cms/backoffice",
"version": "17.3.0-rc",
"version": "17.3.5",
"license": "MIT",
"workspaces": [
"./src/libs/*",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@umbraco-cms/backoffice",
"license": "MIT",
"version": "17.3.3",
"version": "17.3.5",
"type": "module",
"exports": {
".": null,
@@ -582,7 +582,6 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
}
#renderEditAction() {
if (this._isReadOnly) return nothing;
return html`
${when(
this._showContentEdit && this._workspaceEditContentPath,
@@ -616,7 +615,6 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
}
#renderEditSettingsAction() {
if (this._isReadOnly) return nothing;
return html`
${this._hasSettings && this._workspaceEditSettingsPath
? html`
@@ -455,7 +455,6 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
}
#renderEditContentAction() {
if (this._isReadOnly) return nothing;
return this._showContentEdit && this._workspaceEditContentPath
? html`<uui-button
label="edit"
@@ -479,7 +478,6 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper
}
#renderEditSettingsAction() {
if (this._isReadOnly) return nothing;
return html`
${this._hasSettings && this._workspaceEditSettingsPath
? html`<uui-button
@@ -371,7 +371,6 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
}
#renderEditAction() {
if (this._isReadOnly) return nothing;
return this._showContentEdit && this._workspaceEditContentPath
? html`<uui-button
label="edit"
@@ -394,7 +393,6 @@ export class UmbBlockRteEntryElement extends UmbLitElement implements UmbPropert
}
#renderEditSettingsAction() {
if (this._isReadOnly) return nothing;
return html`
${this._hasSettings && this._workspaceEditSettingsPath
? html`<uui-button
@@ -441,7 +441,6 @@ export class UmbBlockSingleEntryElement extends UmbLitElement implements UmbProp
}
#renderEditContentAction() {
if (this._isReadOnly) return nothing;
return this._showContentEdit && this._workspaceEditContentPath
? html`<uui-button
label="edit"
@@ -464,7 +463,6 @@ export class UmbBlockSingleEntryElement extends UmbLitElement implements UmbProp
}
#renderEditSettingsAction() {
if (this._isReadOnly) return nothing;
return html`
${this._hasSettings && this._workspaceEditSettingsPath
? html`<uui-button
@@ -212,12 +212,8 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
};
this.readOnlyGuard?.addRule(rule);
this.content.propertyWriteGuard.addRule({ unique, permitted: false });
this.settings.propertyWriteGuard.addRule({ unique, permitted: false });
} else {
this.readOnlyGuard?.removeRule(unique);
this.content.propertyWriteGuard.removeRule(unique);
this.settings.propertyWriteGuard.removeRule(unique);
}
},
'observeIsReadOnly',
@@ -26,10 +26,6 @@ export const manifests: Array<UmbExtensionManifest> = [
alias: 'Umb.Condition.BlockWorkspaceIsExposed',
match: false,
},
{
alias: 'Umb.Condition.BlockWorkspaceIsReadOnly',
match: false,
},
],
},
{
@@ -51,10 +47,6 @@ export const manifests: Array<UmbExtensionManifest> = [
{
alias: 'Umb.Condition.BlockWorkspaceIsExposed',
},
{
alias: 'Umb.Condition.BlockWorkspaceIsReadOnly',
match: false,
},
],
},
{
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@umbraco/acceptance-test-helpers",
"version": "17.3.3",
"version": "17.3.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/acceptance-test-helpers",
"version": "17.3.3",
"version": "17.3.5",
"description": "Test helpers and builders for making Playwright tests for Umbraco solutions",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
"version": "17.3.3",
"version": "17.3.5",
"assemblyVersion": {
"precision": "build"
},