Sort domains (Culture and Hostnames) (#13797)
* Add sort order to IDomain, UmbracoDomain and DomainDto * Add migration to create domain sort order column * Add Sort method to domain service * Set sort order when persisting new domain and order results * Add multiple and block style support to umb-button-group * Allow sorting domains in back-office, improve UI and rewrite PostSaveLanguageAndDomains for correctly sorting domains * Ensure routing and cache keeps the domain sort order * Update test to assert correct domain order * Move migration to target 11.3 and cleanup plan * Fix formatting/styling and make SelectDomains private Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> --------- Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
This commit is contained in:
@@ -2246,16 +2246,14 @@ public class ContentController : ContentControllerBase
|
||||
|
||||
public ContentDomainsAndCulture GetCultureAndDomains(int id)
|
||||
{
|
||||
IDomain[]? nodeDomains = _domainService.GetAssignedDomains(id, true)?.ToArray();
|
||||
IDomain? wildcard = nodeDomains?.FirstOrDefault(d => d.IsWildcard);
|
||||
IEnumerable<DomainDisplay>? domains = nodeDomains?.Where(d => !d.IsWildcard)
|
||||
.Select(d => new DomainDisplay(d.DomainName, d.LanguageId.GetValueOrDefault(0)));
|
||||
IDomain[] assignedDomains = _domainService.GetAssignedDomains(id, true).ToArray();
|
||||
IDomain? wildcard = assignedDomains.FirstOrDefault(d => d.IsWildcard);
|
||||
IEnumerable<DomainDisplay> domains = assignedDomains.Where(d => !d.IsWildcard).Select(d => new DomainDisplay(d.DomainName, d.LanguageId.GetValueOrDefault(0)));
|
||||
|
||||
return new ContentDomainsAndCulture
|
||||
{
|
||||
Language = wildcard == null || !wildcard.LanguageId.HasValue ? "undefined" : wildcard.LanguageId.ToString(),
|
||||
Domains = domains,
|
||||
Language = wildcard == null || !wildcard.LanguageId.HasValue
|
||||
? "undefined"
|
||||
: wildcard.LanguageId.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2264,11 +2262,11 @@ public class ContentController : ContentControllerBase
|
||||
{
|
||||
if (model.Domains is not null)
|
||||
{
|
||||
foreach (DomainDisplay domain in model.Domains)
|
||||
foreach (DomainDisplay domainDisplay in model.Domains)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri uri = DomainUtilities.ParseUriFromDomainName(domain.Name, new Uri(Request.GetEncodedUrl()));
|
||||
DomainUtilities.ParseUriFromDomainName(domainDisplay.Name, new Uri(Request.GetEncodedUrl()));
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
@@ -2277,18 +2275,16 @@ public class ContentController : ContentControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
// Validate node
|
||||
IContent? node = _contentService.GetById(model.NodeId);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
HttpContext.SetReasonPhrase("Node Not Found.");
|
||||
return NotFound("There is no content node with id {model.NodeId}.");
|
||||
}
|
||||
|
||||
EntityPermission? permission =
|
||||
_userService.GetPermissions(_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, node.Path);
|
||||
|
||||
|
||||
// Validate permissions on node
|
||||
EntityPermission? permission = _userService.GetPermissions(_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, node.Path);
|
||||
if (permission?.AssignedPermissions.Contains(ActionAssignDomain.ActionLetter.ToString(), StringComparer.Ordinal) == false)
|
||||
{
|
||||
HttpContext.SetReasonPhrase("Permission Denied.");
|
||||
@@ -2296,120 +2292,118 @@ public class ContentController : ContentControllerBase
|
||||
}
|
||||
|
||||
model.Valid = true;
|
||||
IDomain[]? domains = _domainService.GetAssignedDomains(model.NodeId, true)?.ToArray();
|
||||
ILanguage[] languages = _localizationService.GetAllLanguages().ToArray();
|
||||
ILanguage? language = model.Language > 0 ? languages.FirstOrDefault(l => l.Id == model.Language) : null;
|
||||
|
||||
// process wildcard
|
||||
if (language != null)
|
||||
IDomain[] assignedDomains = _domainService.GetAssignedDomains(model.NodeId, true).ToArray();
|
||||
ILanguage[] languages = _localizationService.GetAllLanguages().ToArray();
|
||||
|
||||
// Process language
|
||||
ILanguage? language = model.Language > 0 ? languages.FirstOrDefault(l => l.Id == model.Language) : null;
|
||||
if (language is not null)
|
||||
{
|
||||
// yet there is a race condition here...
|
||||
IDomain? wildcard = domains?.FirstOrDefault(d => d.IsWildcard);
|
||||
if (wildcard != null)
|
||||
// Update or create language on wildcard domain
|
||||
IDomain? assignedWildcardDomain = assignedDomains.FirstOrDefault(d => d.IsWildcard);
|
||||
if (assignedWildcardDomain is not null)
|
||||
{
|
||||
wildcard.LanguageId = language.Id;
|
||||
assignedWildcardDomain.LanguageId = language.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
wildcard = new UmbracoDomain("*" + model.NodeId)
|
||||
assignedWildcardDomain = new UmbracoDomain("*" + model.NodeId)
|
||||
{
|
||||
LanguageId = model.Language,
|
||||
RootContentId = model.NodeId
|
||||
};
|
||||
}
|
||||
|
||||
Attempt<OperationResult?> saveAttempt = _domainService.Save(wildcard);
|
||||
if (saveAttempt == false)
|
||||
Attempt<OperationResult?> saveAttempt = _domainService.Save(assignedWildcardDomain);
|
||||
if (saveAttempt.Success == false)
|
||||
{
|
||||
HttpContext.SetReasonPhrase(saveAttempt.Result?.Result.ToString());
|
||||
return BadRequest("Saving domain failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Delete every domain that's in the database, but not in the model
|
||||
foreach (IDomain? assignedDomain in assignedDomains.Where(d => (d.IsWildcard && language is null) || (d.IsWildcard == false && (model.Domains is null || model.Domains.All(m => m.Name.InvariantEquals(d.DomainName) == false)))))
|
||||
{
|
||||
IDomain? wildcard = domains?.FirstOrDefault(d => d.IsWildcard);
|
||||
if (wildcard != null)
|
||||
{
|
||||
_domainService.Delete(wildcard);
|
||||
}
|
||||
_domainService.Delete(assignedDomain);
|
||||
}
|
||||
|
||||
// process domains
|
||||
// delete every (non-wildcard) domain, that exists in the DB yet is not in the model
|
||||
foreach (IDomain domain in domains?.Where(d =>
|
||||
d.IsWildcard == false &&
|
||||
(model.Domains?.All(m => m.Name.InvariantEquals(d.DomainName) == false) ??
|
||||
false)) ??
|
||||
Array.Empty<IDomain>())
|
||||
// Process domains
|
||||
if (model.Domains is not null)
|
||||
{
|
||||
_domainService.Delete(domain);
|
||||
}
|
||||
|
||||
var names = new List<string>();
|
||||
|
||||
// create or update domains in the model
|
||||
foreach (DomainDisplay domainModel in model.Domains?.Where(m => string.IsNullOrWhiteSpace(m.Name) == false) ??
|
||||
Array.Empty<DomainDisplay>())
|
||||
{
|
||||
language = languages.FirstOrDefault(l => l.Id == domainModel.Lang);
|
||||
if (language == null)
|
||||
var savedDomains = new List<IDomain>();
|
||||
foreach (DomainDisplay domainDisplay in model.Domains.Where(m => string.IsNullOrWhiteSpace(m.Name) == false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = domainModel.Name.ToLowerInvariant();
|
||||
if (names.Contains(name))
|
||||
{
|
||||
domainModel.Duplicate = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
names.Add(name);
|
||||
IDomain? domain = domains?.FirstOrDefault(d => d.DomainName.InvariantEquals(domainModel.Name));
|
||||
if (domain != null)
|
||||
{
|
||||
domain.LanguageId = language.Id;
|
||||
_domainService.Save(domain);
|
||||
}
|
||||
else if (_domainService.Exists(domainModel.Name))
|
||||
{
|
||||
domainModel.Duplicate = true;
|
||||
IDomain? xdomain = _domainService.GetByName(domainModel.Name);
|
||||
var xrcid = xdomain?.RootContentId;
|
||||
if (xrcid.HasValue)
|
||||
language = languages.FirstOrDefault(l => l.Id == domainDisplay.Lang);
|
||||
if (language == null)
|
||||
{
|
||||
IContent? xcontent = _contentService.GetById(xrcid.Value);
|
||||
var xnames = new List<string>();
|
||||
while (xcontent != null)
|
||||
continue;
|
||||
}
|
||||
|
||||
var domainName = domainDisplay.Name.ToLowerInvariant();
|
||||
if (savedDomains.Any(d => d.DomainName == domainName))
|
||||
{
|
||||
domainDisplay.Duplicate = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
IDomain? domain = assignedDomains.FirstOrDefault(d => d.DomainName.InvariantEquals(domainName));
|
||||
if (domain is null && _domainService.GetByName(domainName) is IDomain existingDomain)
|
||||
{
|
||||
// Domain name already exists on another node
|
||||
domainDisplay.Duplicate = true;
|
||||
|
||||
// Add node breadcrumbs
|
||||
if (existingDomain.RootContentId is int rootContentId)
|
||||
{
|
||||
if (xcontent.Name is not null)
|
||||
var breadcrumbs = new List<string?>();
|
||||
|
||||
IContent? content = _contentService.GetById(rootContentId);
|
||||
while (content is not null)
|
||||
{
|
||||
xnames.Add(xcontent.Name);
|
||||
breadcrumbs.Add(content.Name);
|
||||
if (content.ParentId < -1)
|
||||
{
|
||||
breadcrumbs.Add("Recycle Bin");
|
||||
}
|
||||
|
||||
content = _contentService.GetParent(content);
|
||||
}
|
||||
|
||||
if (xcontent.ParentId < -1)
|
||||
{
|
||||
xnames.Add("Recycle Bin");
|
||||
}
|
||||
|
||||
xcontent = _contentService.GetParent(xcontent);
|
||||
breadcrumbs.Reverse();
|
||||
domainDisplay.Other = "/" + string.Join("/", breadcrumbs);
|
||||
}
|
||||
|
||||
xnames.Reverse();
|
||||
domainModel.Other = "/" + string.Join("/", xnames);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// yet there is a race condition here...
|
||||
var newDomain = new UmbracoDomain(name) { LanguageId = domainModel.Lang, RootContentId = model.NodeId };
|
||||
Attempt<OperationResult?> saveAttempt = _domainService.Save(newDomain);
|
||||
if (saveAttempt == false)
|
||||
|
||||
// Update or create domain
|
||||
if (domain != null)
|
||||
{
|
||||
domain.LanguageId = language.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
domain = new UmbracoDomain(domainName)
|
||||
{
|
||||
LanguageId = language.Id,
|
||||
RootContentId = model.NodeId,
|
||||
};
|
||||
}
|
||||
|
||||
Attempt<OperationResult?> saveAttempt = _domainService.Save(domain);
|
||||
if (saveAttempt.Success == false)
|
||||
{
|
||||
HttpContext.SetReasonPhrase(saveAttempt.Result?.Result.ToString());
|
||||
return BadRequest("Saving new domain failed");
|
||||
return BadRequest("Saving domain failed");
|
||||
}
|
||||
|
||||
savedDomains.Add(domain);
|
||||
}
|
||||
|
||||
// Sort saved domains
|
||||
_domainService.Sort(savedDomains);
|
||||
}
|
||||
|
||||
model.Valid = model.Domains?.All(m => m.Duplicate == false) ?? false;
|
||||
|
||||
Reference in New Issue
Block a user