Merge remote-tracking branch 'origin/v10/dev' into v11/dev

# Conflicts:
#	src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
#	version.json
This commit is contained in:
Bjarke Berg
2023-01-19 09:38:04 +01:00
19 changed files with 88 additions and 24 deletions

View File

@@ -146,7 +146,7 @@ stages:
inputs:
targetType: inline
script: |
choco install docfx --version=2.59.2 -y
choco install docfx --version=2.59.4 -y
if ($lastexitcode -ne 0){
throw ("Error installing DocFX")
}

View File

@@ -18,6 +18,9 @@
// Set to true if you want the member editable properties shown.
// It will only displays properties marked as "Member can edit" on the "Info" tab of the Member Type.
.WithCustomProperties(false)
// By default the member will be logged in automatically after registration.
// Set this to false if the member should not be logged in automatically.
.WithAutomaticLogIn(true)
.Build();
var success = TempData["FormSuccess"] != null;
@@ -39,7 +42,8 @@ else
new {
MemberTypeAlias = registerModel.MemberTypeAlias,
UsernameIsEmail = registerModel.UsernameIsEmail,
RedirectUrl = registerModel.RedirectUrl
RedirectUrl = registerModel.RedirectUrl,
AutomaticLogIn = registerModel.AutomaticLogIn
}))
{
<h2>Create a new account.</h2>

View File

@@ -36,7 +36,12 @@ public class DatabaseConfigureStep : InstallSetupStep<DatabaseModel>
public override Task<InstallSetupResult?> ExecuteAsync(DatabaseModel databaseSettings)
{
if (!_databaseBuilder.ConfigureDatabaseConnection(databaseSettings, false))
if (databaseSettings is null && string.IsNullOrWhiteSpace(_connectionStrings.CurrentValue.ConnectionString) is false)
{
return Task.FromResult<InstallSetupResult?>(null);
}
if (!_databaseBuilder.ConfigureDatabaseConnection(databaseSettings!, false))
{
throw new InstallException("Could not connect to the database");
}

View File

@@ -2,6 +2,7 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_0_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_2_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_5_0;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade;
@@ -80,5 +81,8 @@ public class UmbracoPlan : MigrationPlan
// To 10.4.0
To<V_10_4_0.AddBlockGridPartialViews>("{3F5D492A-A3DB-43F9-A73E-9FEE3B180E6C}");
// to 10.5.0 / 11.2.0
To<AddPrimaryKeyConstrainToContentVersionCleanupDtos>("{83AF7945-DADE-4A02-9041-F3F6EBFAC319}");
}
}

View File

@@ -0,0 +1,27 @@
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_10_5_0;
public class AddPrimaryKeyConstrainToContentVersionCleanupDtos : MigrationBase
{
public AddPrimaryKeyConstrainToContentVersionCleanupDtos(IMigrationContext context) : base(context)
{
}
protected override void Migrate()
{
IEnumerable<ContentVersionCleanupPolicyDto> contentVersionCleanupPolicyDtos =
Database
.Fetch<ContentVersionCleanupPolicyDto>()
.OrderByDescending(x => x.Updated)
.DistinctBy(x => x.ContentTypeId);
if (TableExists(ContentVersionCleanupPolicyDto.TableName))
{
Delete.Table(ContentVersionCleanupPolicyDto.TableName).Do();
}
Create.Table<ContentVersionCleanupPolicyDto>().Do();
Database.InsertBatch(contentVersionCleanupPolicyDtos);
}
}

View File

@@ -13,7 +13,8 @@ internal class ContentVersionCleanupPolicyDto
public const string TableName = Constants.DatabaseSchema.Tables.ContentVersionCleanupPolicy;
[Column("contentTypeId")]
[ForeignKey(typeof(ContentTypeDto), Column = "nodeId", OnDelete = Rule.Cascade)]
[PrimaryKeyColumn(AutoIncrement = false)]
[ForeignKey(typeof(ContentTypeDto), Column = "nodeId")]
public int ContentTypeId { get; set; }
[Column("preventCleanup")]

View File

@@ -180,6 +180,7 @@ internal class ContentTypeRepository : ContentTypeRepositoryBase<IContentType>,
protected override IEnumerable<string> GetDeleteClauses()
{
var l = (List<string>)base.GetDeleteClauses(); // we know it's a list
l.Add("DELETE FROM umbracoContentVersionCleanupPolicy WHERE contentTypeId = @id");
l.Add("DELETE FROM cmsDocumentType WHERE contentTypeNodeId = @id");
l.Add("DELETE FROM cmsContentType WHERE nodeId = @id");
l.Add("DELETE FROM umbracoNode WHERE id = @id");

View File

@@ -125,13 +125,8 @@ public class MacroRenderingController : UmbracoAuthorizedJsonController
// When rendering the macro in the backoffice the default setting would be to use the Culture of the logged in user.
// Since a Macro might contain thing thats related to the culture of the "IPublishedContent" (ie Dictionary keys) we want
// to set the current culture to the culture related to the content item. This is hacky but it works.
// fixme
// in a 1:1 situation we do not handle the language being edited
// so the macro renders in the wrong language
var culture = DomainUtilities.GetCultureFromDomains(publishedContent.Id, publishedContent.Path, null,
// to set the current culture to the currently edited culture with fallback to the culture related to the content item.
var culture = Request.ClientCulture() ?? DomainUtilities.GetCultureFromDomains(publishedContent.Id, publishedContent.Path, null,
umbracoContext, _siteDomainHelper);
if (culture != null)

View File

@@ -158,6 +158,9 @@
items: ".umb-group-builder__property-sortable",
stop: (e, ui) => {
updatePropertiesSortOrder();
// when a property is dropped we need to reset the requested tab hover alias
scope.sortableRequestedTabAlias = undefined;
}
};

View File

@@ -153,8 +153,10 @@
.umb-minilistview {
.umb-table-row.not-allowed {
cursor: not-allowed;
.umb-minilistview__fade-not-allowed {
opacity: 0.6;
cursor: not-allowed;
}
}
div.umb-mini-list-view__breadcrumb {

View File

@@ -30,7 +30,11 @@
};
vm.$onChanges = function () {
vm.icon = vm.elementTypeModel ? vm.elementTypeModel.icon.split(" ")[0] : 'icon-block';
vm.icon = vm.elementTypeModel ? vm.elementTypeModel.icon : 'icon-block';
if (vm.blockConfigModel.iconColor) {
// enforce configured icon color for catalogue appearance instead of icon color from element type
vm.icon = vm.icon.split(" ")[0];
}
};
vm.$onDestroy = function () {

View File

@@ -64,12 +64,12 @@
ng-class="{'-selected':child.selected, 'not-allowed':!child.allowed}">
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':child.published === false}">
<div class="flex items-center">
<umb-icon icon="icon-navigation-right" class="umb-table__row-expand" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.metaData.hasChildren !== true}">&nbsp;</umb-icon>
<umb-icon icon="{{child.icon}}" class="umb-table-body__icon umb-table-body__fileicon"></umb-icon>
<umb-icon icon="icon-navigation-right" class="umb-table__row-expand cursor-pointer" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.metaData.hasChildren !== true}">&nbsp;</umb-icon>
<umb-icon icon="{{child.icon}}" class="umb-table-body__icon umb-table-body__fileicon umb-minilistview__fade-not-allowed"></umb-icon>
<umb-icon icon="icon-check" class="umb-table-body__icon umb-table-body__checkicon"></umb-icon>
</div>
</div>
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':child.published === false}">{{ child.name }}</div>
<div class="umb-table-cell black umb-minilistview__fade-not-allowed" ng-class="{'umb-table-cell--faded':child.published === false}">{{ child.name }}</div>
</div>
<!-- Show a message when no items are found, depending on whether you searched or the list was empty anyway -->

View File

@@ -64,7 +64,6 @@
function onInit() {
vm.variants = $scope.model.variants;
vm.availableVariants = vm.variants.filter(saveableVariantFilter);
vm.isNew = vm.variants.some(variant => variant.state === 'NotCreated');
if (!$scope.model.title) {
localizationService.localize("content_readyToSave").then(value => {
@@ -78,7 +77,7 @@
variant.save = variant.publish = false;
variant.isMandatory = isMandatoryFilter(variant);
if(vm.isNew && hasAnyData(variant) && allowUpdate(variant)) {
if(variant.state === 'NotCreated' && hasAnyData(variant) && allowUpdate(variant)) {
variant.save = true;
}
});

View File

@@ -31,7 +31,7 @@
<div class="umb-block-list__actions" ng-if="vm.loading !== true && !vm.singleBlockMode">
<button
id="{{vm.model.alias}}"
id="button_{{vm.model.alias}}"
type="button"
class="btn-reset umb-block-list__create-button umb-outline"
ng-disabled="vm.availableBlockTypes.length === 0 || vm.readonly"

View File

@@ -246,7 +246,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
}
else if ($scope.model.config.startNode.query) {
//if we have a query for the startnode, we will use that.
var rootId = $routeParams.id;
var rootId = editorState.current.id;
entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
dialogOptions.startNodeId = ($scope.model.config.idType === "udi" ? ent.udi : ent.id).toString();
});

View File

@@ -100,7 +100,7 @@
</div>
<button ng-if="vm.loading !== true && ((vm.singleMode === true && vm.model.value.length === 0) || vm.singleMode !== true)"
id="{{vm.model.alias}}"
id="button_{{vm.model.alias}}"
type="button"
class="btn-reset umb-media-card-grid__create-button umb-outline"
ng-disabled="!vm.allowAddMedia"

View File

@@ -95,6 +95,12 @@ public class UmbRegisterController : SurfaceController
{
model.UsernameIsEmail = usernameIsEmail.ToString() == "True";
}
if (RouteData.Values.TryGetValue(nameof(RegisterModel.AutomaticLogIn), out var automaticLogin) &&
automaticLogin != null)
{
model.AutomaticLogIn = automaticLogin.ToString() == "True";
}
}
private void AddErrors(IdentityResult result)
@@ -109,9 +115,8 @@ public class UmbRegisterController : SurfaceController
/// Registers a new member.
/// </summary>
/// <param name="model">Register member model.</param>
/// <param name="logMemberIn">Flag for whether to log the member in upon successful registration.</param>
/// <returns>Result of registration operation.</returns>
private async Task<IdentityResult> RegisterMemberAsync(RegisterModel model, bool logMemberIn = true)
private async Task<IdentityResult> RegisterMemberAsync(RegisterModel model)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
@@ -149,7 +154,7 @@ public class UmbRegisterController : SurfaceController
_memberService.Save(member);
if (logMemberIn)
if (model.AutomaticLogIn)
{
await _memberSignInManager.SignInAsync(identityUser, false);
}

View File

@@ -13,6 +13,7 @@ public class RegisterModel : PostRedirectModel
MemberTypeAlias = Constants.Conventions.MemberTypes.DefaultAlias;
UsernameIsEmail = true;
MemberProperties = new List<MemberPropertyModel>();
AutomaticLogIn = true;
}
[Required]
@@ -59,4 +60,9 @@ public class RegisterModel : PostRedirectModel
/// Flag to determine if the username should be the email address, if true then the Username property is ignored
/// </summary>
public bool UsernameIsEmail { get; set; }
/// <summary>
/// Flag to determine if the member should be logged in automatically after successful registration
/// </summary>
public bool AutomaticLogIn { get; set; }
}

View File

@@ -14,6 +14,7 @@ public class RegisterModelBuilder : MemberModelBuilderBase
private string? _memberTypeAlias;
private string? _redirectUrl;
private bool _usernameIsEmail;
private bool _automaticLogIn = true;
public RegisterModelBuilder(IMemberTypeService memberTypeService, IShortStringHelper shortStringHelper)
: base(memberTypeService, shortStringHelper)
@@ -44,6 +45,12 @@ public class RegisterModelBuilder : MemberModelBuilderBase
return this;
}
public RegisterModelBuilder WithAutomaticLogIn(bool automaticLogIn = true)
{
_automaticLogIn = automaticLogIn;
return this;
}
public RegisterModel Build()
{
var providedOrDefaultMemberTypeAlias = _memberTypeAlias ?? Constants.Conventions.MemberTypes.DefaultAlias;
@@ -62,6 +69,7 @@ public class RegisterModelBuilder : MemberModelBuilderBase
MemberProperties = _lookupProperties
? GetMemberPropertiesViewModel(memberType)
: Enumerable.Empty<MemberPropertyModel>().ToList(),
AutomaticLogIn = _automaticLogIn
};
return model;
}