private bool IsPropertyModified(HookedEntity entry, string propertyName)
        {
            var result = false;

            if (entry.State != EntityState.Detached)
            {
                var prop = entry.Entry.Property(propertyName);
                if (prop != null)
                {
                    switch (entry.State)
                    {
                    case EntityState.Added:
                        // OriginalValues cannot be used for entities in the Added state.
                        result = prop.CurrentValue != null;
                        break;

                    case EntityState.Deleted:
                        // CurrentValues cannot be used for entities in the Deleted state.
                        result = prop.OriginalValue != null;
                        break;

                    default:
                        result =
                            (prop.CurrentValue != null && !prop.CurrentValue.Equals(prop.OriginalValue)) ||
                            (prop.OriginalValue != null && !prop.OriginalValue.Equals(prop.CurrentValue));
                        break;
                    }
                }
            }

            return(result);
        }
Example #2
0
        protected override void OnDeleting(BaseEntity entity, HookedEntity entry)
        {
            var type = entry.Entity.GetUnproxiedType();

            if (!_candidateTypes.Contains(type))
            {
                return;
            }

            if (type == typeof(ProductAttributeOption))
            {
                var pictureId = ((ProductAttributeOption)entry.Entity).PictureId;
                if (pictureId != 0)
                {
                    _toDelete.Add(pictureId);
                }
            }
            else if (type == typeof(ProductAttributeOptionsSet))
            {
                var options = _productAttributeService.Value.GetProductAttributeOptionsByOptionsSetId(entity.Id);
                _toDelete.AddRange(options.Where(x => x.PictureId != 0).Select(x => x.PictureId));
            }
            else if (type == typeof(ProductAttribute))
            {
                var options = _productAttributeService.Value.GetProductAttributeOptionsByAttributeId(entity.Id);
                _toDelete.AddRange(options.Where(x => x.PictureId != 0).Select(x => x.PictureId));
            }
            else if (type == typeof(ProductVariantAttribute))
            {
                var options = _productAttributeService.Value.GetProductVariantAttributeValues(entity.Id);
                _toDelete.AddRange(options.Where(x => x.PictureId != 0).Select(x => x.PictureId));
            }
        }
        protected override void OnDeleted(ILocalizedEntity entity, HookedEntity entry)
        {
            var entityType        = entry.Entity.GetUnproxiedType();
            var localizedEntities = _localizedEntityService.Value.GetLocalizedProperties(entry.Entity.Id, entityType.Name);

            _toDelete.AddRange(localizedEntities);
        }
Example #4
0
        protected override void OnDeleted(ISlugSupported entity, HookedEntity entry)
        {
            var entityType = entry.Entity.GetUnproxiedType();
            var records    = _urlRecordService.Value.GetUrlRecordsFor(entityType.Name, entry.Entity.Id);

            _toDelete.AddRange(records);
        }
Example #5
0
        protected override void OnDeleted(IStoreMappingSupported entity, HookedEntity entry)
        {
            var entityType = entry.Entity.GetUnproxiedType();

            var records = _storeMappingService.Value
                          .GetStoreMappingsFor(entityType.Name, entry.Entity.Id)
                          .ToList();

            _toDelete.AddRange(records);
        }
        protected override void OnDeleting(BaseEntity entity, HookedEntity entry)
        {
            var type = entry.Entity.GetUnproxiedType();

            if (!_candidateTypes.Contains(type))
            {
                return;
            }

            if (type == typeof(SpecificationAttribute))
            {
                var attribute        = (SpecificationAttribute)entry.Entity;
                var attributeOptions = attribute.SpecificationAttributeOptions.ToList();
                if (!attributeOptions.Any())
                {
                    attributeOptions = _specificationAttributeService.Value.GetSpecificationAttributeOptionsBySpecificationAttribute(attribute.Id).ToList();
                }

                attributeOptions.ForEach(x => _toDelete.AddRange(_localizedEntityService.Value.GetLocalizedProperties(x.Id, "SpecificationAttributeOption")));
            }
            else if (type == typeof(ProductVariantAttribute))
            {
                var attribute        = (ProductVariantAttribute)entry.Entity;
                var attributeOptions = attribute.ProductVariantAttributeValues.ToList();
                if (!attributeOptions.Any())
                {
                    attributeOptions = _productAttributeService.Value.GetProductVariantAttributeValues(attribute.Id).ToList();
                }

                attributeOptions.ForEach(x => _toDelete.AddRange(_localizedEntityService.Value.GetLocalizedProperties(x.Id, "ProductVariantAttributeValue")));
            }
            else if (type == typeof(ProductAttribute))
            {
                var optionIds = (
                    from a in _productAttributeRepository.Value.TableUntracked
                    from os in a.ProductAttributeOptionsSets
                    from ao in os.ProductAttributeOptions
                    where a.Id == entry.Entity.Id
                    select ao.Id).ToList();

                optionIds.ForEach(x => _toDelete.AddRange(_localizedEntityService.Value.GetLocalizedProperties(x, "ProductAttributeOption")));
            }
            else if (type == typeof(ProductAttributeOptionsSet))
            {
                var set = (ProductAttributeOptionsSet)entry.Entity;
                var attributeOptions = set.ProductAttributeOptions.ToList();
                if (!attributeOptions.Any())
                {
                    attributeOptions = _productAttributeService.Value.GetProductAttributeOptionsByOptionsSetId(set.Id).ToList();
                }

                attributeOptions.ForEach(x => _toDelete.AddRange(_localizedEntityService.Value.GetLocalizedProperties(x.Id, "ProductAttributeOption")));
            }
        }
Example #7
0
        protected override void OnUpdating(ISoftDeletable entity, HookedEntity entry)
        {
            var baseEntity = entry.Entity;

            var prop            = entry.Entry.Property("Deleted");
            var deletedModified = !prop.CurrentValue.Equals(prop.OriginalValue);

            if (!deletedModified)
            {
                return;
            }

            var entityType = baseEntity.GetUnproxiedType();

            // mark orphaned ACL records as idle
            var aclSupported = baseEntity as IAclSupported;

            if (aclSupported != null && aclSupported.SubjectToAcl)
            {
                var shouldSetIdle = entity.Deleted;
                var rsAclRecord   = _ctx.Resolve <IRepository <AclRecord> >();

                var aclService = _ctx.Resolve <IAclService>();
                var records    = aclService.GetAclRecordsFor(entityType.Name, baseEntity.Id);
                foreach (var record in records)
                {
                    record.IsIdle = shouldSetIdle;
                    aclService.UpdateAclRecord(record);
                }
            }

            // Delete orphaned inactive UrlRecords.
            // We keep the active ones on purpose in order to be able to fully restore a soft deletable entity once we implemented the "recycle bin" feature
            var slugSupported = baseEntity as ISlugSupported;

            if (slugSupported != null && entity.Deleted)
            {
                var rsUrlRecord = _ctx.Resolve <IRepository <UrlRecord> >();

                var urlRecordService = _ctx.Resolve <IUrlRecordService>();
                var activeRecords    = urlRecordService.GetUrlRecordsFor(entityType.Name, baseEntity.Id);
                using (urlRecordService.BeginScope())
                {
                    foreach (var record in activeRecords)
                    {
                        if (!record.IsActive)
                        {
                            urlRecordService.DeleteUrlRecord(record);
                        }
                    }
                }
            }
        }
Example #8
0
        protected override void OnInserting(IAuditable entity, HookedEntity entry)
        {
            var now = DateTime.UtcNow;

            if (entity.CreatedOnUtc == DateTime.MinValue)
            {
                entity.CreatedOnUtc = now;
            }

            if (entity.UpdatedOnUtc == DateTime.MinValue)
            {
                entity.UpdatedOnUtc = now;
            }
        }
Example #9
0
        public void OnBeforeSave(HookedEntity entry)
        {
            var entity = entry.Entity;

            if (entity is Product && entry.InitialState == EntityState.Modified)
            {
                var modProps = _dbContext.GetModifiedProperties(entity);

                if (modProps.Keys.Any(x => _countAffectingProductProps.Contains(x)))
                {
                    Invalidate(true);
                }
            }
        }
        private void RevertChanges(HookedEntity entry, string errorMessage)
        {
            // throw exception in OnBeforeSaveCompleted
            _errorMessage = errorMessage;

            // revert changes
            if (entry.Entry.State == System.Data.Entity.EntityState.Modified)
            {
                entry.Entry.State = System.Data.Entity.EntityState.Unchanged;
            }
            else if (entry.Entry.State == System.Data.Entity.EntityState.Added)
            {
                entry.Entry.State = System.Data.Entity.EntityState.Detached;
            }
        }
        private bool HasEntityDuplicate <TEntity>(
            HookedEntity entry,
            BaseEntity baseEntity,
            Func <TEntity, string> getName,
            Expression <Func <TEntity, bool> > getDuplicate) where TEntity : BaseEntity
        {
            if (entry.InitialState == EntityState.Added || entry.InitialState == EntityState.Modified)
            {
                var repository  = _ctx.Resolve <IRepository <TEntity> >();
                var allEntities = repository.TableUntracked as IQueryable <TEntity>;

                var existingEntity = allEntities.FirstOrDefault(getDuplicate);
                if (existingEntity != null && existingEntity.Id != baseEntity.Id)
                {
                    RevertChanges(entry, string.Concat(T("Common.Error.OptionAlreadyExists", getName(existingEntity).NaIfEmpty()), " ", T("Common.Error.ChooseDifferentValue")));
                    return(true);
                }
            }

            return(false);
        }
        private bool HasAliasDuplicate <T1, T2>(HookedEntity entry, BaseEntity baseEntity) where T1 : BaseEntity where T2 : BaseEntity
        {
            if (entry.InitialState == EntityState.Added || entry.InitialState == EntityState.Modified)
            {
                var entity = baseEntity as ISearchAlias;
                if (entity != null)
                {
                    entity.Alias = SeoExtensions.GetSeName(entity.Alias);
                    if (entity.Alias.HasValue())
                    {
                        var entities1 = _ctx.Resolve <IRepository <T1> >().TableUntracked as IQueryable <ISearchAlias>;
                        var entities2 = _ctx.Resolve <IRepository <T2> >().TableUntracked as IQueryable <ISearchAlias>;

                        var duplicate1 = entities1.FirstOrDefault(x => x.Alias == entity.Alias);
                        var duplicate2 = entities2.FirstOrDefault(x => x.Alias == entity.Alias);

                        if (duplicate1 != null || duplicate2 != null)
                        {
                            var type = baseEntity.GetUnproxiedType();

                            if (duplicate1 != null && duplicate1.Id == entity.Id && type == typeof(T1))
                            {
                                return(false);
                            }
                            if (duplicate2 != null && duplicate2.Id == entity.Id && type == typeof(T2))
                            {
                                return(false);
                            }

                            RevertChanges(entry, string.Concat(T("Common.Error.AliasAlreadyExists", entity.Alias), " ", T("Common.Error.ChooseDifferentValue")));
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        private bool HasAliasDuplicate <TEntity>(
            HookedEntity entry,
            BaseEntity baseEntity,
            Func <IQueryable <TEntity>, TEntity, bool> hasDuplicate = null)
            where TEntity : BaseEntity
        {
            if (entry.InitialState == EntityState.Added || entry.InitialState == EntityState.Modified)
            {
                var entity = baseEntity as ISearchAlias;
                if (entity != null)
                {
                    entity.Alias = SeoExtensions.GetSeName(entity.Alias);
                    if (entity.Alias.HasValue())
                    {
                        var repository  = _ctx.Resolve <IRepository <TEntity> >();
                        var allEntities = repository.TableUntracked as IQueryable <ISearchAlias>;

                        //if (allEntities != null && allEntities.Any(x => x.Id != entity.Id && x.Alias == entity.Alias))
                        if (allEntities != null)
                        {
                            var duplicateExists = hasDuplicate == null
                                                                ? allEntities.Any(x => x.Id != entity.Id && x.Alias == entity.Alias)
                                                                : hasDuplicate(repository.TableUntracked, (TEntity)entity);

                            if (duplicateExists)
                            {
                                RevertChanges(entry, string.Concat(T("Common.Error.AliasAlreadyExists", entity.Alias), " ", T("Common.Error.ChooseDifferentValue")));
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Example #14
0
 protected override void OnUpdating(IAuditable entity, HookedEntity entry)
 {
     entity.UpdatedOnUtc = DateTime.UtcNow;
 }
 protected override void OnDeleted(ProductVariantAttributeValue entity, HookedEntity entry)
 {
     _toDelete.Add(entity);
 }
        private void HookObject(BaseEntity baseEntity, HookedEntity entry)
        {
            var type = baseEntity.GetUnproxiedType();

            if (!_candidateTypes.Contains(type))
            {
                return;
            }

            if (type == typeof(SpecificationAttribute))
            {
                if (HasAliasDuplicate <ProductAttribute, SpecificationAttribute>(entry, baseEntity))
                {
                    return;
                }

                if (IsPropertyModified(entry, "Alias"))
                {
                    _catalogSearchQueryAliasMapper.Value.ClearAttributeCache();
                }
            }
            else if (type == typeof(SpecificationAttributeOption))
            {
                var entity = (SpecificationAttributeOption)baseEntity;

                if (HasEntityDuplicate <SpecificationAttributeOption>(entry, baseEntity, x => x.Name,
                                                                      x => x.SpecificationAttributeId == entity.SpecificationAttributeId && x.Name == entity.Name))
                {
                    return;
                }

                if (HasAliasDuplicate <SpecificationAttributeOption>(entry, baseEntity))
                {
                    return;
                }

                if (IsPropertyModified(entry, "Alias"))
                {
                    _catalogSearchQueryAliasMapper.Value.ClearAttributeCache();
                }
            }
            else if (type == typeof(ProductSpecificationAttribute))
            {
                var entity = (ProductSpecificationAttribute)baseEntity;

                if (HasEntityDuplicate <ProductSpecificationAttribute>(entry, baseEntity, x => x.SpecificationAttributeOption?.Name,
                                                                       x => x.ProductId == entity.ProductId && x.SpecificationAttributeOptionId == entity.SpecificationAttributeOptionId))
                {
                    return;
                }
            }
            else if (type == typeof(ProductAttribute))
            {
                if (HasAliasDuplicate <ProductAttribute, SpecificationAttribute>(entry, baseEntity))
                {
                    return;
                }

                if (IsPropertyModified(entry, "Alias"))
                {
                    _catalogSearchQueryAliasMapper.Value.ClearVariantCache();
                }
            }
            else if (type == typeof(ProductAttributeOption))
            {
                var entity = (ProductAttributeOption)baseEntity;

                if (HasEntityDuplicate <ProductAttributeOption>(entry, baseEntity, x => x.Name,
                                                                x => x.ProductAttributeOptionsSetId == entity.ProductAttributeOptionsSetId && x.Name == entity.Name))
                {
                    return;
                }

                // ClearVariantCache() not necessary
                if (HasAliasDuplicate <ProductAttributeOption>(entry, baseEntity))
                {
                    return;
                }
            }
            else if (type == typeof(ProductVariantAttribute))
            {
                var entity = (ProductVariantAttribute)baseEntity;

                if (HasEntityDuplicate <ProductVariantAttribute>(entry, baseEntity, x => x.ProductAttribute?.Name,
                                                                 x => x.ProductId == entity.ProductId && x.ProductAttributeId == entity.ProductAttributeId))
                {
                    return;
                }
            }
            else if (type == typeof(ProductVariantAttributeValue))
            {
                var entity = (ProductVariantAttributeValue)baseEntity;

                if (HasEntityDuplicate <ProductVariantAttributeValue>(entry, baseEntity, x => x.Name,
                                                                      x => x.ProductVariantAttributeId == entity.ProductVariantAttributeId && x.Name == entity.Name))
                {
                    return;
                }

                if (HasAliasDuplicate <ProductVariantAttributeValue>(entry, baseEntity,
                                                                     (all, e) => all.Any(x => x.Id != e.Id && x.ProductVariantAttributeId == e.ProductVariantAttributeId && x.Alias == e.Alias)))
                {
                    return;
                }

                if (IsPropertyModified(entry, "Alias"))
                {
                    _catalogSearchQueryAliasMapper.Value.ClearVariantCache();
                }
            }
            else if (type == typeof(LocalizedProperty))
            {
                // note: not fired when SpecificationAttribute or SpecificationAttributeOption deleted.
                // not necessary anyway because cache cleared by above code.
                var prop     = (LocalizedProperty)baseEntity;
                var keyGroup = prop.LocaleKeyGroup;

                if (!prop.LocaleKey.IsCaseInsensitiveEqual("Alias"))
                {
                    return;
                }

                // validating ProductVariantAttributeValue goes too far here.
                if (!keyGroup.IsCaseInsensitiveEqual("SpecificationAttribute") &&
                    !keyGroup.IsCaseInsensitiveEqual("SpecificationAttributeOption") &&
                    !keyGroup.IsCaseInsensitiveEqual("ProductAttribute") &&
                    !keyGroup.IsCaseInsensitiveEqual("ProductAttributeOption"))
                {
                    return;
                }

                // check alias duplicate
                if (entry.InitialState == EntityState.Added || entry.InitialState == EntityState.Modified)
                {
                    prop.LocaleValue = SeoExtensions.GetSeName(prop.LocaleValue);
                    if (prop.LocaleValue.HasValue() && HasAliasDuplicate(prop))
                    {
                        RevertChanges(entry, string.Concat(T("Common.Error.AliasAlreadyExists", prop.LocaleValue), " ", T("Common.Error.ChooseDifferentValue")));
                        return;
                    }
                }

                if (IsPropertyModified(entry, "LocaleValue"))
                {
                    if (keyGroup.IsCaseInsensitiveEqual("SpecificationAttribute") || keyGroup.IsCaseInsensitiveEqual("SpecificationAttributeOption"))
                    {
                        _catalogSearchQueryAliasMapper.Value.ClearAttributeCache();
                    }
                    else if (keyGroup.IsCaseInsensitiveEqual("ProductAttribute") || keyGroup.IsCaseInsensitiveEqual("ProductVariantAttributeValue"))
                    {
                        // not necessary for ProductAttributeOption
                        _catalogSearchQueryAliasMapper.Value.ClearVariantCache();
                    }
                }
            }
        }
 protected override void OnUpdating(BaseEntity entity, HookedEntity entry)
 {
     HookObject(entity, entry);
 }
Example #18
0
        public void OnAfterSave(HookedEntity entry)
        {
            if (_invalidated)
            {
                // Don't bother processing.
                return;
            }

            // INFO: Acl & StoreMapping affect element counts

            var entity = entry.Entity;

            if (entity is Product)
            {
                if (entry.InitialState == EntityState.Added)
                {
                    Invalidate(true);
                }
            }
            else if (entity is Category)
            {
                Invalidate();
            }
            else if (entity is Language || entity is CustomerRole)
            {
                InvalidateWhen(entry.InitialState == EntityState.Modified || entry.InitialState == EntityState.Deleted);
            }
            else if (entity is Setting)
            {
                var name = (entity as Setting).Name.ToLowerInvariant();
                InvalidateWhen(name == "catalogsettings.showcategoryproductnumber" || name == "catalogsettings.showcategoryproductnumberincludingsubcategories");
            }
            else if (entity is ProductCategory)
            {
                Invalidate(true);
            }
            else if (entity is AclRecord)
            {
                var acl = entity as AclRecord;
                if (!acl.IsIdle)
                {
                    if (acl.EntityName == "Product")
                    {
                        Invalidate(true);
                    }
                    else if (acl.EntityName == "Category")
                    {
                        Invalidate(false);
                    }
                }
            }
            else if (entity is StoreMapping)
            {
                var stm = entity as StoreMapping;
                if (stm.EntityName == "Product")
                {
                    Invalidate(true);
                }
                else if (stm.EntityName == "Category")
                {
                    Invalidate(false);
                }
            }
            else if (entity is LocalizedProperty)
            {
                var lp  = entity as LocalizedProperty;
                var key = lp.LocaleKey;
                if (lp.LocaleKeyGroup == "Category" && (key == "Name" || key == "FullName" || key == "Description" || key == "BadgeText"))
                {
                    Invalidate();
                }
            }
        }