/// <summary>
        /// Updates settings for a store.
        /// </summary>
        /// <param name="settings">Settings class instance.</param>
        /// <param name="form">Form value collection.</param>
        /// <param name="storeId">Store identifier.</param>
        /// <param name="settingService">Setting service.</param>
        /// <param name="propertyNameMapper">Function to map property names. Return <c>null</c> to skip a property.</param>
        public async Task UpdateSettingsAsync(
            object settings,
            IFormCollection form,
            int storeId,
            Func <string, string> propertyNameMapper = null)
        {
            var settingType       = settings.GetType();
            var settingName       = settingType.Name;
            var settingProperties = FastProperty.GetProperties(settingType).Values;

            foreach (var prop in settingProperties)
            {
                var name = propertyNameMapper?.Invoke(prop.Name) ?? prop.Name;

                if (!name.HasValue())
                {
                    continue;
                }

                var key = string.Concat(settingName, ".", name);

                if (storeId == 0 || IsOverrideChecked(key, form))
                {
                    dynamic value = prop.GetValue(settings);
                    await _settingService.ApplySettingAsync(key, value ?? string.Empty, storeId);
                }
                else if (storeId > 0)
                {
                    await _settingService.RemoveSettingAsync(key, storeId);
                }
            }

            await _db.SaveChangesAsync();
        }
示例#2
0
        public ApplySettingResult ApplyUserSetting <T>(ProviderMetadata metadata, Expression <Func <ProviderMetadata, T> > propertyAccessor)
        {
            Guard.NotNull(metadata, nameof(metadata));
            Guard.NotNull(propertyAccessor, nameof(propertyAccessor));

            var settingKey = metadata.SettingKeyPattern.FormatInvariant(metadata.SystemName, propertyAccessor.ExtractPropertyInfo().Name);
            var value      = propertyAccessor.Compile().Invoke(metadata);

            return(_settingService.ApplySettingAsync(settingKey, value).Await());
        }
示例#3
0
        /// <summary>
        /// Applies setting value. The caller is responsible for database commit.
        /// </summary>
        /// <typeparam name="T">Entity type</typeparam>
        /// <typeparam name="TPropType">Property type</typeparam>
        /// <param name="settings">Settings</param>
        /// <param name="keySelector">Key selector</param>
        /// <param name="storeId">Store ID</param>
        public static async Task <ApplySettingResult> ApplySettingAsync <T, TPropType>(this ISettingService service,
                                                                                       T settings,
                                                                                       Expression <Func <T, TPropType> > keySelector,
                                                                                       int storeId = 0)
            where T : ISettings, new()
        {
            var propInfo = keySelector.ExtractPropertyInfo();
            var key      = string.Concat(typeof(T).Name, ".", propInfo.Name);

            // Duck typing is not supported in C#. That's why we're using dynamic type.
            var     fastProp     = FastProperty.GetProperty(propInfo, PropertyCachingStrategy.EagerCached);
            dynamic currentValue = fastProp.GetValue(settings);

            return(await service.ApplySettingAsync(key, currentValue, storeId));
        }
示例#4
0
        /// <summary>
        /// Applies or removes a setting property. The caller is responsible for database commit.
        /// </summary>
        /// <typeparam name="T">Entity type</typeparam>
        /// <typeparam name="TPropType">Property type</typeparam>
        /// <param name="settings">Settings</param>
        /// <param name="keySelector">Key selector</param>
        /// <param name="storeId">Store ID</param>
        /// <returns><c>true</c> when the setting property has been modified.</returns>
        public static async Task <ApplySettingResult> UpdateSettingAsync <T, TPropType>(this ISettingService service,
                                                                                        T settings,
                                                                                        Expression <Func <T, TPropType> > keySelector,
                                                                                        bool overrideForStore,
                                                                                        int storeId = 0) where T : ISettings, new()
        {
            if (overrideForStore || storeId == 0)
            {
                return(await service.ApplySettingAsync(settings, keySelector, storeId));
            }
            else if (storeId > 0 && await service.RemoveSettingAsync(settings, keySelector, storeId))
            {
                return(ApplySettingResult.Deleted);
            }

            return(ApplySettingResult.Unchanged);
        }
示例#5
0
        public async Task Run(TaskExecutionContext ctx, CancellationToken cancelToken = default)
        {
            if (!_currencySettings.AutoUpdateEnabled)
            {
                return;
            }

            long     lastUpdateTimeTicks = _currencySettings.LastUpdateTime;
            DateTime lastUpdateTime      = DateTime.FromBinary(lastUpdateTimeTicks);

            lastUpdateTime = DateTime.SpecifyKind(lastUpdateTime, DateTimeKind.Utc);

            // Don't update currencies if last execution time is less then an hour in the past.
            if (lastUpdateTime.AddHours(1) < DateTime.UtcNow)
            {
                var exchangeRates = await _currencyService
                                    .GetCurrencyLiveRatesAsync(_storeContext.CurrentStore.PrimaryExchangeRateCurrency.CurrencyCode);

                var currencyCodes = exchangeRates.Select(x => x.CurrencyCode).Distinct().ToArray();
                var currencies    = await _db.Currencies
                                    .Where(x => currencyCodes.Contains(x.CurrencyCode))
                                    .ToDictionaryAsync(x => x.CurrencyCode, StringComparer.OrdinalIgnoreCase);

                foreach (var exchageRate in exchangeRates)
                {
                    if (currencies.TryGetValue(exchageRate.CurrencyCode, out var currency) && currency.Rate != exchageRate.Rate)
                    {
                        currency.Rate = exchageRate.Rate;
                    }
                }

                // Save new current date as last execution time.
                _currencySettings.LastUpdateTime = DateTime.UtcNow.ToBinary();
                await _settingService.ApplySettingAsync(_currencySettings, x => x.LastUpdateTime);

                await _db.SaveChangesAsync(cancelToken);
            }
        }
示例#6
0
        public virtual async Task <bool> MoveAsync(
            Provider <IMediaStorageProvider> sourceProvider,
            Provider <IMediaStorageProvider> targetProvider,
            CancellationToken cancelToken = default)
        {
            Guard.NotNull(sourceProvider, nameof(sourceProvider));
            Guard.NotNull(targetProvider, nameof(targetProvider));

            // Source must support sending
            if (sourceProvider.Value is not IMediaSender sender)
            {
                throw new ArgumentException(T("Admin.Media.StorageMovingNotSupported", sourceProvider.Metadata.SystemName));
            }

            // Target must support receiving
            if (targetProvider.Value is not IMediaReceiver receiver)
            {
                throw new ArgumentException(T("Admin.Media.StorageMovingNotSupported", targetProvider.Metadata.SystemName));
            }

            // Source and target provider must not be equal
            if (sender == receiver)
            {
                throw new ArgumentException(T("Admin.Media.CannotMoveToSameProvider"));
            }

            var success = false;
            var utcNow  = DateTime.UtcNow;
            var context = new MediaMoverContext(sender, receiver);

            // We are about to process data in chunks but want to commit ALL at once after ALL chunks have been processed successfully.
            // AutoDetectChanges true required for newly inserted binary data.
            using (var scope = new DbContextScope(ctx: _db, autoDetectChanges: true, retainConnection: true))
            {
                using (var transaction = await _db.Database.BeginTransactionAsync(cancelToken))
                {
                    try
                    {
                        var pager = new FastPager <MediaFile>(_db.MediaFiles, PAGE_SIZE);
                        while ((await pager.ReadNextPageAsync <MediaFile>()).Out(out var files))
                        {
                            if (cancelToken.IsCancellationRequested)
                            {
                                break;
                            }

                            foreach (var file in files)
                            {
                                // Move item from source to target
                                await sender.MoveToAsync(receiver, context, file);

                                file.UpdatedOnUtc = utcNow;
                                ++context.MovedItems;
                            }

                            if (!cancelToken.IsCancellationRequested)
                            {
                                await _db.SaveChangesAsync(cancelToken);

                                // Detach all entities from previous page to save memory
                                scope.DbContext.DetachEntities(files, deep: true);
                            }
                        }

                        if (!cancelToken.IsCancellationRequested)
                        {
                            await transaction.CommitAsync(cancelToken);

                            success = true;
                        }
                        else
                        {
                            success = false;
                            await transaction.RollbackAsync(CancellationToken.None);
                        }
                    }
                    catch (Exception exception)
                    {
                        success = false;
                        await transaction.RollbackAsync(cancelToken);

                        _notifier.Error(exception);
                        Logger.Error(exception);
                    }
                }
            }


            if (success)
            {
                await _settingService.ApplySettingAsync("Media.Storage.Provider", targetProvider.Metadata.SystemName);

                await _db.SaveChangesAsync(cancelToken);
            }

            // Inform both provider about ending
            await sender.OnCompletedAsync(context, success, cancelToken);

            await receiver.OnCompletedAsync(context, success, cancelToken);

            return(success);
        }