using BusinessLogic.Entities; using BusinessLogic.Interfaces.Persistence; using BusinessLogic.Interfaces.Repositories; using BusinessLogic.Interfaces.Security; using DataAccess.Interfaces; using log4net; using System; using System.Data.Entity; using System.Linq; using System.Web; namespace DataAccess.Persistence { public sealed class UnitOfWork : IUnitOfWork, IDisposable { private readonly IncomeDbContext _context; private readonly ISecurityContext _securityContext; private readonly IAuditLogger _auditLogger; private readonly ILog _log; #region Repositories public IAccountHolderRepository AccountHolders { get; private set; } public IAccountReferenceValidatorRepository AccountReferenceValidators { get; private set; } public IActivityLogRepository ActivityLogs { get; private set; } public ICheckDigitConfigurationRepository CheckDigitConfigurations { get; private set; } public IEReturnRepository EReturns { get; private set; } public IEReturnCashRepository EReturnCashes { get; private set; } public IEReturnChequeRepository EReturnCheques { get; private set; } public IEReturnStatusRepository EReturnStatuses { get; private set; } public IEReturnTemplateRepository EReturnTemplates { get; private set; } public IEReturnTemplateRowRepository EReturnTemplateRows { get; private set; } public IEReturnTypeRepository EReturnTypes { get; private set; } public IRepository EReturnNotes { get; private set; } public IFundRepository Funds { get; private set; } public IFundMetadataRepository FundMetadatas { get; private set; } public IFundGroupRepository FundGroups { get; private set; } public IFundGroupFundRepository FundGroupFunds { get; private set; } public IMethodOfPaymentRepository Mops { get; private set; } public IMethodOfPaymentMetadataRepository MopMetadatas { get; private set; } public IMetadataKeyRepository MetadataKeys { get; private set; } public IOfficeRepository Offices { get; private set; } public IPendingTransactionRepository PendingTransactions { get; private set; } public IRoleRepository Roles { get; private set; } public IFundMessageRepository FundMessages { get; private set; } public IFundMessageMetadataRepository FundMessageMetadata { get; private set; } public ISystemMessageRepository SystemMessages { get; private set; } public ISuspenseRepository Suspenses { get; private set; } public IRepository SuspenseNotes { get; private set; } public ITransactionRepository Transactions { get; private set; } public IUserRepository Users { get; private set; } public IUserFundGroupRepository UserFundGroups { get; private set; } public IUserRoleRepository UserRoles { get; private set; } public IUserTemplateRepository UserTemplates { get; private set; } public IUserMethodOfPaymentRepository UserMethodOfPayments { get; private set; } public IVatRepository Vats { get; private set; } public IVatMetadataRepository VatMetadatas { get; private set; } public IPaymentIntegrationRepository PaymentIntegrations { get; private set; } public IImportProcessingRuleRepository ImportProcessingRules { get; private set; } public IImportProcessingRuleConditionRepository ImportProcessingRuleConditions { get; private set; } public IImportProcessingRuleActionRepository ImportProcessingRuleActions { get; private set; } public IRepository ImportProcessingRuleFields { get; private set; } public IRepository ImportProcessingRuleOperators { get; private set; } public IFileImportRepository FileImports { get; private set; } public IImportRepository Imports { get; private set; } public IRepository ImportRows { get; private set; } public IImportTypeRepository ImportTypes { get; private set; } public IImportTypeImportProcessingRuleRepository ImportTypeImportProcessingRules { get; private set; } #endregion public UnitOfWork(IncomeDbContext context, ISecurityContext securityContext, IAccountHolderRepository accountHolderRepository, IAccountReferenceValidatorRepository accountReferenceValidatorRepository, IActivityLogRepository activityLogRepository, ICheckDigitConfigurationRepository checkDigitConfigurationRepository, IEReturnRepository eReturnRepository, IEReturnCashRepository eReturnCashesRepository, IEReturnChequeRepository eReturnChequesRepository, IEReturnStatusRepository eReturnStatusRepository, IEReturnTemplateRepository eReturnTemplates, IEReturnTemplateRowRepository eReturnTemplateRows, IEReturnTypeRepository eReturnTypeRepository, IRepository eReturnNotesRepository, IFundRepository fundRepository, IFundMetadataRepository fundMetadataRepository, IFundGroupRepository fundGroupRepository, IFundGroupFundRepository fundGroupFundRepository, IMethodOfPaymentRepository mopRepository, IMethodOfPaymentMetadataRepository mopMetadataRepository, IMetadataKeyRepository mopMetadataKeyRepository, IOfficeRepository officeRepository, IPendingTransactionRepository pendingTransactionRepository, IRoleRepository roleRepository, IFundMessageRepository fundMessageRepository, IFundMessageMetadataRepository fundMessageMetadataRepository, ISystemMessageRepository systemMessageRepository, ISuspenseRepository suspenseRepository, IRepository suspenseNoteRepository, ITransactionRepository transactionRepository, IUserRepository userRepository, IUserFundGroupRepository userFundGroupRepository, IUserRoleRepository userRoleRepository, IUserTemplateRepository userTemplateRepository, IUserMethodOfPaymentRepository userPostPaymentMopCodeRepository, IVatRepository vatRepository, IVatMetadataRepository VatMetadataRepository, IPaymentIntegrationRepository paymentIntegrationRepository, IImportProcessingRuleRepository importProcessingRuleRepository, IImportProcessingRuleConditionRepository importProcessingRuleConditionRepository, IImportProcessingRuleActionRepository importProcessingRuleActionRepository, IRepository importProcessingRuleFieldRepository, IRepository importProcessingRuleOperatorRepository, IFileImportRepository fileImports, IImportTypeRepository importTypes, IImportTypeImportProcessingRuleRepository importTypeImportProcessingRules, IImportRepository importsRepository, IRepository importRowRepository, IAuditLogger auditLogger, ILog log) { _context = context; _securityContext = securityContext; AccountHolders = accountHolderRepository; AccountReferenceValidators = accountReferenceValidatorRepository; ActivityLogs = activityLogRepository; CheckDigitConfigurations = checkDigitConfigurationRepository; EReturns = eReturnRepository; EReturnCashes = eReturnCashesRepository; EReturnCheques = eReturnChequesRepository; EReturnStatuses = eReturnStatusRepository; EReturnTemplates = eReturnTemplates; EReturnTemplateRows = eReturnTemplateRows; EReturnTypes = eReturnTypeRepository; EReturnNotes = eReturnNotesRepository; Funds = fundRepository; FundMetadatas = fundMetadataRepository; FundGroups = fundGroupRepository; FundGroupFunds = fundGroupFundRepository; Mops = mopRepository; MopMetadatas = mopMetadataRepository; MetadataKeys = mopMetadataKeyRepository; Offices = officeRepository; PendingTransactions = pendingTransactionRepository; Roles = roleRepository; FundMessages = fundMessageRepository; FundMessageMetadata = fundMessageMetadataRepository; Suspenses = suspenseRepository; SuspenseNotes = suspenseNoteRepository; SystemMessages = systemMessageRepository; Transactions = transactionRepository; Users = userRepository; UserFundGroups = userFundGroupRepository; UserRoles = userRoleRepository; UserTemplates = userTemplateRepository; UserMethodOfPayments = userPostPaymentMopCodeRepository; Vats = vatRepository; VatMetadatas = VatMetadataRepository; PaymentIntegrations = paymentIntegrationRepository; ImportProcessingRules = importProcessingRuleRepository; ImportProcessingRuleConditions = importProcessingRuleConditionRepository; ImportProcessingRuleActions = importProcessingRuleActionRepository; ImportProcessingRuleFields = importProcessingRuleFieldRepository; ImportProcessingRuleOperators = importProcessingRuleOperatorRepository; FileImports = fileImports; ImportTypes = importTypes; ImportTypeImportProcessingRules = importTypeImportProcessingRules; Imports = importsRepository; ImportRows = importRowRepository; _auditLogger = auditLogger; _log = log; ApplyFilters(); } public int Complete(int userId) { try { _auditLogger.CreateAudit(_context, userId); } catch (Exception e) { _log.Error(e); } // Note: Could we wrap this in a try catch and call ResetChanges if there is a problem? // Means we don't have to handle it in the consuming code - it's all handled here. return _context.SaveChanges(); } public int CompleteWithoutAudit(int userId) { // Note: Could we wrap this in a try catch and call ResetChanges if there is a problem? // Means we don't have to handle it in the consuming code - it's all handled here. return _context.SaveChanges(); } // Note: See note above in Complete. We could potentially make this private and handle all rollbacks in this class, rather than consuming code. public void ResetChanges() { foreach (var change in _context.ChangeTracker.Entries()) { switch (change.State) { case EntityState.Modified: case EntityState.Deleted: change.State = EntityState.Modified; change.State = EntityState.Unchanged; break; case EntityState.Added: change.State = EntityState.Detached; break; } } } public void Dispose() { _context.Dispose(); } #region Private methods private void ApplyFilters() { if (!HttpContext.Current.User.Identity.IsAuthenticated) return; // Super user - no filters! if (_securityContext.IsSuperUser) return; if (_securityContext.IsPublicUser) { // Filter out things here that public users can shouldn't see return; }; // We only need to get this data once... var userAccessibleFunds = _securityContext.AccessibleFundCodes; var userAccessibleTemplates = _securityContext.AccessibleTemplates.Select(x => Convert.ToInt32(x)); // Now apply restrictions. // This idea here is that we're not repeating the restrictions in several places. // I didn't want to include them in the repository as this isn't repository // specific code (you oculd argue it isn't UoW specific code - but it does // seem to fit a little better in here). Transactions.AddFilter(x => userAccessibleFunds.Contains(x.FundCode)); AccountHolders.AddFilter(x => userAccessibleFunds.Contains(x.FundCode)); Funds.AddFilter(x => userAccessibleFunds.Contains(x.FundCode)); FundGroupFunds.AddFilter(x => userAccessibleFunds.Contains(x.Fund.FundCode)); if (!_securityContext.IsInRole(BusinessLogic.Security.Role.Finance) && !_securityContext.IsInRole(BusinessLogic.Security.Role.ChequeProcess)) { EReturnTemplates.AddFilter(x => userAccessibleTemplates.Contains(x.Id)); EReturns.AddFilter(x => userAccessibleTemplates.Contains(x.Template.Id)); } } #endregion } }