using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Dictionary;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Models.Mapping
{
///
/// A custom tab/property resolver for members which will ensure that the built-in membership properties are or aren't displayed
/// depending on if the member type has these properties
///
///
/// This also ensures that the IsLocked out property is readonly when the member is not locked out - this is because
/// an admin cannot actually set isLockedOut = true, they can only unlock.
///
public class MemberTabsAndPropertiesMapper : TabsAndPropertiesMapper
{
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly ILocalizedTextService _localizedTextService;
private readonly IMemberTypeService _memberTypeService;
private readonly IMemberService _memberService;
private readonly IMemberGroupService _memberGroupService;
private readonly MemberPasswordConfigurationSettings _memberPasswordConfiguration;
private readonly PropertyEditorCollection _propertyEditorCollection;
public MemberTabsAndPropertiesMapper(ICultureDictionary cultureDictionary,
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
ILocalizedTextService localizedTextService,
IMemberTypeService memberTypeService,
IMemberService memberService,
IMemberGroupService memberGroupService,
IOptions memberPasswordConfiguration,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
PropertyEditorCollection propertyEditorCollection)
: base(cultureDictionary, localizedTextService, contentTypeBaseServiceProvider)
{
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
_localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
_memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService));
_memberService = memberService ?? throw new ArgumentNullException(nameof(memberService));
_memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService));
_memberPasswordConfiguration = memberPasswordConfiguration.Value;
_propertyEditorCollection = propertyEditorCollection;
}
///
/// Overridden to deal with custom member properties and permissions.
public override IEnumerable> Map(IMember source, MapperContext context)
{
var memberType = _memberTypeService.Get(source.ContentTypeId);
IgnoreProperties = memberType.CompositionPropertyTypes
.Where(x => x.HasIdentity == false)
.Select(x => x.Alias)
.ToArray();
var resolved = base.Map(source, context);
// This is kind of a hack because a developer is supposed to be allowed to set their property editor - would have been much easier
// if we just had all of the membership provider fields on the member table :(
// TODO: But is there a way to map the IMember.IsLockedOut to the property ? i dunno.
var isLockedOutProperty = resolved.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == Constants.Conventions.Member.IsLockedOut);
if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1")
{
isLockedOutProperty.View = "readonlyvalue";
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
}
if (_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
&& _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var memberTypeLink = $"#/member/memberTypes/edit/{source.ContentTypeId}";
// Replace the doctype property
var docTypeProperty = resolved.SelectMany(x => x.Properties)
.First(x => x.Alias == $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype");
docTypeProperty.Value = new List