<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofoundry.Domain.Data;
using Cofoundry.Domain.CQS;
using Microsoft.EntityFrameworkCore;
using Cofoundry.Core;
using Cofoundry.Core.Data;

namespace Cofoundry.Domain
{
    public class DuplicateCustomEntityCommandHandler
        : IAsyncCommandHandler<DuplicateCustomEntityCommand>
        , IIgnorePermissionCheckHandler
    {
        private readonly ICommandExecutor _commandExecutor;
        private readonly CofoundryDbContext _dbContext;
        private readonly ICustomEntityStoredProcedures _customEntityStoredProcedures;
        private readonly ITransactionScopeManager _transactionScopeFactory;
        private readonly ICustomEntityDataModelMapper _customEntityDataModelMapper;

        public DuplicateCustomEntityCommandHandler(
            ICommandExecutor commandExecutor,
            CofoundryDbContext dbContext,
            ICustomEntityStoredProcedures customEntityStoredProcedures,
            ITransactionScopeManager transactionScopeFactory,
            ICustomEntityDataModelMapper customEntityDataModelMapper
            )
        {
            _commandExecutor = commandExecutor;
            _dbContext = dbContext;
            _customEntityStoredProcedures = customEntityStoredProcedures;
            _transactionScopeFactory = transactionScopeFactory;
            _customEntityDataModelMapper = customEntityDataModelMapper;
        }

        public async Task ExecuteAsync(DuplicateCustomEntityCommand command, IExecutionContext executionContext)
        {
            var customEntityToDuplicate = await GetCustomEntityToDuplicateAsync(command);
            var addCustomEntityCommand = MapCommand(command, customEntityToDuplicate);

            using (var scope = _transactionScopeFactory.Create(_dbContext))
            {
                // Note: the underlying AddCustomEntityCommand will enforce permissions
                await _commandExecutor.ExecuteAsync(addCustomEntityCommand, executionContext);

                await _customEntityStoredProcedures.CopyBlocksToDraftAsync(
                    addCustomEntityCommand.OutputCustomEntityId,
                    customEntityToDuplicate.CustomEntityVersionId);

                await scope.CompleteAsync();
            }

            // Set Ouput
            command.OutputCustomEntityId = addCustomEntityCommand.OutputCustomEntityId;
        }

        private Task<CustomEntityVersion> GetCustomEntityToDuplicateAsync(DuplicateCustomEntityCommand command)
        {
            return _dbContext
                .CustomEntityVersions
                .AsNoTracking()
                .Include(e => e.CustomEntity)
                .FilterActive()
                .FilterByCustomEntityId(command.CustomEntityToDuplicateId)
                .OrderByLatest()
                .FirstOrDefaultAsync();
        }

        private AddCustomEntityCommand MapCommand(DuplicateCustomEntityCommand command, CustomEntityVersion customEntityVersionToDuplicate)
        {
            EntityNotFoundException.ThrowIfNull(customEntityVersionToDuplicate, command.CustomEntityToDuplicateId);

            var addPageCommand = new AddCustomEntityCommand();
            addPageCommand.Title = command.Title;
            addPageCommand.LocaleId = command.LocaleId;
            addPageCommand.UrlSlug = command.UrlSlug;
            addPageCommand.CustomEntityDefinitionCode = customEntityVersionToDuplicate.CustomEntity.CustomEntityDefinitionCode;
            addPageCommand.Model = _customEntityDataModelMapper.Map(addPageCommand.CustomEntityDefinitionCode, customEntityVersionToDuplicate.SerializedData);

            return addPageCommand;
        }
    }
}<commit_msg>Fixes #242 - Custom Entity Duplication<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofoundry.Domain.Data;
using Cofoundry.Domain.CQS;
using Microsoft.EntityFrameworkCore;
using Cofoundry.Core;
using Cofoundry.Core.Data;

namespace Cofoundry.Domain
{
    public class DuplicateCustomEntityCommandHandler
        : IAsyncCommandHandler<DuplicateCustomEntityCommand>
        , IIgnorePermissionCheckHandler
    {
        private readonly ICommandExecutor _commandExecutor;
        private readonly CofoundryDbContext _dbContext;
        private readonly ICustomEntityStoredProcedures _customEntityStoredProcedures;
        private readonly ITransactionScopeManager _transactionScopeFactory;
        private readonly ICustomEntityDataModelMapper _customEntityDataModelMapper;
        private readonly ICustomEntityDefinitionRepository _customEntityDefinitionRepository;

        public DuplicateCustomEntityCommandHandler(
            ICommandExecutor commandExecutor,
            CofoundryDbContext dbContext,
            ICustomEntityStoredProcedures customEntityStoredProcedures,
            ITransactionScopeManager transactionScopeFactory,
            ICustomEntityDataModelMapper customEntityDataModelMapper,
            ICustomEntityDefinitionRepository customEntityDefinitionRepository
            )
        {
            _commandExecutor = commandExecutor;
            _dbContext = dbContext;
            _customEntityStoredProcedures = customEntityStoredProcedures;
            _transactionScopeFactory = transactionScopeFactory;
            _customEntityDataModelMapper = customEntityDataModelMapper;
            _customEntityDefinitionRepository = customEntityDefinitionRepository;
        }

        public async Task ExecuteAsync(DuplicateCustomEntityCommand command, IExecutionContext executionContext)
        {
            var customEntityToDuplicate = await GetCustomEntityToDuplicateAsync(command);
            var definition = _customEntityDefinitionRepository.GetByCode(customEntityToDuplicate.CustomEntity.CustomEntityDefinitionCode);
            var addCustomEntityCommand = MapCommand(command, customEntityToDuplicate);

            using (var scope = _transactionScopeFactory.Create(_dbContext))
            {
                // Note: the underlying AddCustomEntityCommand will enforce permissions
                await _commandExecutor.ExecuteAsync(addCustomEntityCommand, executionContext);

                await _customEntityStoredProcedures.CopyBlocksToDraftAsync(
                    addCustomEntityCommand.OutputCustomEntityId,
                    customEntityToDuplicate.CustomEntityVersionId);

                if (definition.AutoPublish)
                {
                    var publishCommand = new PublishCustomEntityCommand(addCustomEntityCommand.OutputCustomEntityId);
                    await _commandExecutor.ExecuteAsync(publishCommand);
                }

                await scope.CompleteAsync();
            }

            // Set Ouput
            command.OutputCustomEntityId = addCustomEntityCommand.OutputCustomEntityId;
        }

        private Task<CustomEntityVersion> GetCustomEntityToDuplicateAsync(DuplicateCustomEntityCommand command)
        {
            return _dbContext
                .CustomEntityVersions
                .AsNoTracking()
                .Include(e => e.CustomEntity)
                .FilterActive()
                .FilterByCustomEntityId(command.CustomEntityToDuplicateId)
                .OrderByLatest()
                .FirstOrDefaultAsync();
        }

        private AddCustomEntityCommand MapCommand(
            DuplicateCustomEntityCommand command, 
            CustomEntityVersion customEntityVersionToDuplicate
            )
        {
            EntityNotFoundException.ThrowIfNull(customEntityVersionToDuplicate, command.CustomEntityToDuplicateId);

            var addCustomEntityCommand = new AddCustomEntityCommand();
            addCustomEntityCommand.Title = command.Title;
            addCustomEntityCommand.LocaleId = command.LocaleId;
            addCustomEntityCommand.UrlSlug = command.UrlSlug;
            addCustomEntityCommand.CustomEntityDefinitionCode = customEntityVersionToDuplicate.CustomEntity.CustomEntityDefinitionCode;
            addCustomEntityCommand.Model = _customEntityDataModelMapper.Map(addCustomEntityCommand.CustomEntityDefinitionCode, customEntityVersionToDuplicate.SerializedData);
            
            return addCustomEntityCommand;
        }
    }
}
{'fraction_non_alphanumeric': 0.04612435605606805, 'fraction_numerical': 0.0003594105666706601, 'mean_word_length': 2.947044917257683, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5221862', 'n_tokens_mistral': 1895, 'n_tokens_neox': 1855, 'n_words': 318}