using Nop.Core; using Nop.Core.Caching; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Stores; using Nop.Data; namespace Nop.Services.Stores; /// /// Store mapping service /// public partial class StoreMappingService : IStoreMappingService { #region Fields protected readonly CatalogSettings _catalogSettings; protected readonly IRepository _storeMappingRepository; protected readonly IStaticCacheManager _staticCacheManager; protected readonly IStoreContext _storeContext; #endregion #region Ctor public StoreMappingService(CatalogSettings catalogSettings, IRepository storeMappingRepository, IStaticCacheManager staticCacheManager, IStoreContext storeContext) { _catalogSettings = catalogSettings; _storeMappingRepository = storeMappingRepository; _staticCacheManager = staticCacheManager; _storeContext = storeContext; } #endregion #region Utilities /// /// Inserts a store mapping record /// /// Store mapping /// A task that represents the asynchronous operation protected virtual async Task InsertStoreMappingAsync(StoreMapping storeMapping) { await _storeMappingRepository.InsertAsync(storeMapping); } /// /// Get a value indicating whether a store mapping exists for an entity type /// /// Type of entity that supports store mapping /// /// A task that represents the asynchronous operation /// The task result contains true if exists; otherwise false /// protected virtual async Task IsEntityMappingExistsAsync() where TEntity : BaseEntity, IStoreMappingSupported { var entityName = typeof(TEntity).Name; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopStoreDefaults.StoreMappingExistsCacheKey, entityName); var query = from sm in _storeMappingRepository.Table where sm.EntityName == entityName select sm.StoreId; return await _staticCacheManager.GetAsync(key, query.Any); } #endregion #region Methods /// /// Apply store mapping to the passed query /// /// Type of entity that supports store mapping /// Query to filter /// Store identifier /// /// A task that represents the asynchronous operation /// The task result contains the filtered query /// public virtual async Task> ApplyStoreMapping(IQueryable query, int storeId) where TEntity : BaseEntity, IStoreMappingSupported { ArgumentNullException.ThrowIfNull(query); if (storeId == 0 || _catalogSettings.IgnoreStoreLimitations || !await IsEntityMappingExistsAsync()) return query; return from entity in query where !entity.LimitedToStores || _storeMappingRepository.Table.Any(sm => sm.EntityName == typeof(TEntity).Name && sm.EntityId == entity.Id && sm.StoreId == storeId) select entity; } /// /// Deletes a store mapping record /// /// Store mapping record /// A task that represents the asynchronous operation public virtual async Task DeleteStoreMappingAsync(StoreMapping storeMapping) { await _storeMappingRepository.DeleteAsync(storeMapping); } /// /// Gets store mapping records /// /// Type of entity that supports store mapping /// Entity /// /// A task that represents the asynchronous operation /// The task result contains the store mapping records /// public virtual async Task> GetStoreMappingsAsync(TEntity entity) where TEntity : BaseEntity, IStoreMappingSupported { ArgumentNullException.ThrowIfNull(entity); var entityId = entity.Id; var entityName = entity.GetType().Name; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopStoreDefaults.StoreMappingsCacheKey, entityId, entityName); var query = from sm in _storeMappingRepository.Table where sm.EntityId == entityId && sm.EntityName == entityName select sm; var storeMappings = await _staticCacheManager.GetAsync(key, async () => await query.ToListAsync()); return storeMappings; } /// /// Inserts a store mapping record /// /// Type of entity that supports store mapping /// Entity /// Store id /// A task that represents the asynchronous operation public virtual async Task InsertStoreMappingAsync(TEntity entity, int storeId) where TEntity : BaseEntity, IStoreMappingSupported { ArgumentNullException.ThrowIfNull(entity); if (storeId == 0) throw new ArgumentOutOfRangeException(nameof(storeId)); var entityId = entity.Id; var entityName = entity.GetType().Name; var storeMapping = new StoreMapping { EntityId = entityId, EntityName = entityName, StoreId = storeId }; await InsertStoreMappingAsync(storeMapping); } /// /// Find store identifiers with granted access (mapped to the entity) /// /// Type of entity that supports store mapping /// Entity /// /// A task that represents the asynchronous operation /// The task result contains the store identifiers /// public virtual async Task GetStoresIdsWithAccessAsync(TEntity entity) where TEntity : BaseEntity, IStoreMappingSupported { ArgumentNullException.ThrowIfNull(entity); var entityId = entity.Id; var entityName = entity.GetType().Name; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopStoreDefaults.StoreMappingIdsCacheKey, entityId, entityName); var query = from sm in _storeMappingRepository.Table where sm.EntityId == entityId && sm.EntityName == entityName select sm.StoreId; return await _staticCacheManager.GetAsync(key, () => query.ToArray()); } /// /// Find store identifiers with granted access (mapped to the entity) /// /// Type of entity that supports store mapping /// Entity /// /// The store identifiers /// public virtual int[] GetStoresIdsWithAccess(TEntity entity) where TEntity : BaseEntity, IStoreMappingSupported { ArgumentNullException.ThrowIfNull(entity); var entityId = entity.Id; var entityName = entity.GetType().Name; var key = _staticCacheManager.PrepareKeyForDefaultCache(NopStoreDefaults.StoreMappingIdsCacheKey, entityId, entityName); var query = from sm in _storeMappingRepository.Table where sm.EntityId == entityId && sm.EntityName == entityName select sm.StoreId; return _staticCacheManager.Get(key, () => query.ToArray()); } /// /// Authorize whether entity could be accessed in the current store (mapped to this store) /// /// Type of entity that supports store mapping /// Entity /// /// A task that represents the asynchronous operation /// The task result contains true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(TEntity entity) where TEntity : BaseEntity, IStoreMappingSupported { var store = await _storeContext.GetCurrentStoreAsync(); return await AuthorizeAsync(entity, store.Id); } /// /// Authorize whether entity could be accessed in a store (mapped to this store) /// /// Type of entity that supports store mapping /// Entity /// Store identifier /// /// A task that represents the asynchronous operation /// The task result contains true - authorized; otherwise, false /// public virtual async Task AuthorizeAsync(TEntity entity, int storeId) where TEntity : BaseEntity, IStoreMappingSupported { if (entity == null) return false; if (storeId == 0) //return true if no store specified/found return true; if (_catalogSettings.IgnoreStoreLimitations) return true; if (!entity.LimitedToStores) return true; foreach (var storeIdWithAccess in await GetStoresIdsWithAccessAsync(entity)) if (storeId == storeIdWithAccess) //yes, we have such permission return true; //no permission found return false; } /// /// Authorize whether entity could be accessed in a store (mapped to this store) /// /// Type of entity that supports store mapping /// Entity /// Store identifier /// /// True - authorized; otherwise, false /// public virtual bool Authorize(TEntity entity, int storeId) where TEntity : BaseEntity, IStoreMappingSupported { if (entity == null) return false; if (storeId == 0) //return true if no store specified/found return true; if (_catalogSettings.IgnoreStoreLimitations) return true; if (!entity.LimitedToStores) return true; foreach (var storeIdWithAccess in GetStoresIdsWithAccess(entity)) if (storeId == storeIdWithAccess) //yes, we have such permission return true; //no permission found return false; } #endregion }