using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Security; using Umbraco.Extensions; namespace Umbraco.Cms.Core.ContentApps; public class ContentAppFactoryCollection : BuilderCollectionBase { private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly ILogger _logger; public ContentAppFactoryCollection( Func> items, ILogger logger, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) : base(items) { _logger = logger; _backOfficeSecurityAccessor = backOfficeSecurityAccessor; } public IEnumerable GetContentAppsFor(object o, IEnumerable? userGroups = null) { IEnumerable roles = GetCurrentUserGroups(); var apps = this.Select(x => x.GetContentAppFor(o, roles)).WhereNotNull().OrderBy(x => x.Weight).ToList(); var aliases = new HashSet(); List? dups = null; foreach (ContentApp app in apps) { if (app.Alias is not null) { if (aliases.Contains(app.Alias)) { (dups ??= new List()).Add(app.Alias); } else { aliases.Add(app.Alias); } } } if (dups != null) { // dying is not user-friendly, so let's write to log instead, and wish people read logs... // throw new InvalidOperationException($"Duplicate content app aliases found: {string.Join(",", dups)}"); _logger.LogWarning("Duplicate content app aliases found: {DuplicateAliases}", string.Join(",", dups)); } return apps; } private IEnumerable GetCurrentUserGroups() { IUser? currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser; return currentUser == null ? Enumerable.Empty() : currentUser.Groups; } }