"
},
new Topic
@@ -3913,7 +3921,9 @@ public IList Topics()
SystemName = "LoginRegistrationInfo",
IncludeInSitemap = false,
IsPasswordProtected = false,
- Title = "About login / registration",
+ RenderAsWidget = true,
+ WidgetWrapContent = false,
+ Title = "About login / registration",
Body = "
Not registered yet?
Create your own account now and experience our diversity. With an account you can place orders faster and will always have a perfect overview of your current and previous orders.
"
},
new Topic
From c6661e7b1c2ba5c8209a01afdcf8384af04e5952 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Thu, 2 May 2019 16:16:48 +0200
Subject: [PATCH 007/262] Fixes menu editing exception when only one language
is installed
---
.../SmartStore.Data/Utilities/DataMigrator.cs | 2 +-
.../Administration/Controllers/MenuController.cs | 16 +++++++++++-----
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/src/Libraries/SmartStore.Data/Utilities/DataMigrator.cs b/src/Libraries/SmartStore.Data/Utilities/DataMigrator.cs
index 569d41af2f..b93c7ca64b 100644
--- a/src/Libraries/SmartStore.Data/Utilities/DataMigrator.cs
+++ b/src/Libraries/SmartStore.Data/Utilities/DataMigrator.cs
@@ -558,7 +558,7 @@ public static void CreateSystemMenus(IDbContext context)
IsSystemMenu = true,
Published = true,
Template = "Dropdown",
- Title = GetResource("Menu.ServiceMenu")
+ Title = GetResource("Menu.ServiceMenu").NullEmpty() ?? "Service"
});
scope.Commit();
diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
index 527bf324dc..01f658c981 100644
--- a/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
+++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
@@ -549,18 +549,24 @@ private void PrepareModel(MenuItemRecordModel model, MenuItemRecord entity)
private void UpdateLocales(MenuRecord entity, MenuRecordModel model)
{
- foreach (var localized in model.Locales)
+ if (model.Locales != null)
{
- _localizedEntityService.SaveLocalizedValue(entity, x => x.Title, localized.Title, localized.LanguageId);
+ foreach (var localized in model.Locales)
+ {
+ _localizedEntityService.SaveLocalizedValue(entity, x => x.Title, localized.Title, localized.LanguageId);
+ }
}
}
private void UpdateLocales(MenuItemRecord entity, MenuItemRecordModel model)
{
- foreach (var localized in model.Locales)
+ if (model.Locales != null)
{
- _localizedEntityService.SaveLocalizedValue(entity, x => x.Title, localized.Title, localized.LanguageId);
- _localizedEntityService.SaveLocalizedValue(entity, x => x.ShortDescription, localized.ShortDescription, localized.LanguageId);
+ foreach (var localized in model.Locales)
+ {
+ _localizedEntityService.SaveLocalizedValue(entity, x => x.Title, localized.Title, localized.LanguageId);
+ _localizedEntityService.SaveLocalizedValue(entity, x => x.ShortDescription, localized.ShortDescription, localized.LanguageId);
+ }
}
}
From 7985093b32865b85bcd930925f024630845155c1 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Thu, 2 May 2019 21:29:50 +0200
Subject: [PATCH 008/262] Added TabbableModel and publishing of ModelBoundEvent
for menu item editing
---
.../Controllers/MenuController.cs | 8 +-
.../Models/Menus/MenuItemRecordModel.cs | 2 +-
.../Views/Menu/_CreateOrUpdate.Item.cshtml | 292 +++++++++---------
.../Views/Menu/_CreateOrUpdate.cshtml | 4 +-
4 files changed, 160 insertions(+), 146 deletions(-)
diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
index 01f658c981..88255b9e60 100644
--- a/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
+++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MenuController.cs
@@ -285,7 +285,7 @@ public ActionResult CreateItem(string providerName, int menuId, int parentItemId
// Do not name parameter "model" because of property of same name.
[HttpPost, ValidateInput(false), ParameterBasedOnFormName("save-item-continue", "continueEditing")]
- public ActionResult CreateItem(MenuItemRecordModel itemModel, bool continueEditing)
+ public ActionResult CreateItem(MenuItemRecordModel itemModel, bool continueEditing, FormCollection form)
{
if (!Services.Permissions.Authorize(StandardPermissionProvider.ManageMenus))
{
@@ -301,6 +301,8 @@ public ActionResult CreateItem(MenuItemRecordModel itemModel, bool continueEditi
_menuStorage.InsertMenuItem(item);
UpdateLocales(item, itemModel);
+
+ Services.EventPublisher.Publish(new ModelBoundEvent(itemModel, item, form));
NotifySuccess(T("Admin.Common.DataSuccessfullySaved"));
if (continueEditing)
@@ -345,7 +347,7 @@ public ActionResult EditItem(int id)
// Do not name parameter "model" because of property of same name.
[HttpPost, ValidateInput(false), ParameterBasedOnFormName("save-item-continue", "continueEditing")]
- public ActionResult EditItem(MenuItemRecordModel itemModel, bool continueEditing)
+ public ActionResult EditItem(MenuItemRecordModel itemModel, bool continueEditing, FormCollection form)
{
if (!Services.Permissions.Authorize(StandardPermissionProvider.ManageMenus))
{
@@ -367,6 +369,8 @@ public ActionResult EditItem(MenuItemRecordModel itemModel, bool continueEditing
_menuStorage.UpdateMenuItem(item);
UpdateLocales(item, itemModel);
+
+ Services.EventPublisher.Publish(new ModelBoundEvent(itemModel, item, form));
NotifySuccess(T("Admin.Common.DataSuccessfullySaved"));
if (continueEditing)
diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Menus/MenuItemRecordModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Menus/MenuItemRecordModel.cs
index 2db3ae4c5b..c4c5dd22f4 100644
--- a/src/Presentation/SmartStore.Web/Administration/Models/Menus/MenuItemRecordModel.cs
+++ b/src/Presentation/SmartStore.Web/Administration/Models/Menus/MenuItemRecordModel.cs
@@ -12,7 +12,7 @@
namespace SmartStore.Admin.Models.Menus
{
[Validator(typeof(MenuItemRecordValidator))]
- public class MenuItemRecordModel : EntityModelBase, IIcon, ILocalizedModel
+ public class MenuItemRecordModel : TabbableModel, IIcon, ILocalizedModel
{
public int MenuId { get; set; }
public string Model { get; set; }
diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.Item.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.Item.cshtml
index caebd48800..c5fe940eb0 100644
--- a/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.Item.cshtml
+++ b/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.Item.cshtml
@@ -6,167 +6,177 @@
@Html.HiddenFor(model => model.MenuId)
@Html.HiddenFor(model => model.ProviderName)
-
- @*IMPORTANT: Do not delete, this hidden element contains the id to assign localized values to the corresponding language *@
- @Html.HiddenFor(model => model.Locales[item].LanguageId)
+
+ @*IMPORTANT: Do not delete, this hidden element contains the id to assign localized values to the corresponding language *@
+ @Html.HiddenFor(model => model.Locales[item].LanguageId)
- @Html.EditorFor(model => model.Locales[item].Title)
- @Html.ValidationMessageFor(model => model.Locales[item].Title)
-
+}
\ No newline at end of file
diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.cshtml
index 9d9886e418..f24e5a84fc 100644
--- a/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.cshtml
+++ b/src/Presentation/SmartStore.Web/Administration/Views/Menu/_CreateOrUpdate.cshtml
@@ -7,14 +7,14 @@
@Html.SmartStore().TabStrip().Name("menu-edit").Style(TabsStyle.Material).Items(x =>
{
- x.Add().Text(T("Admin.Common.General").Text).Content(TabInfo()).Selected(true);
+ x.Add().Text(T("Admin.Common.General").Text).Content(TabGeneral()).Selected(true);
x.Add().Text(T("Admin.Catalog.Categories.Acl").Text).Content(TabAcl());
x.Add().Text(T("Admin.Common.Stores").Text).Content(TabStores());
EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "menu-edit", this.Html, this.Model));
})
-@helper TabInfo()
+@helper TabGeneral()
{
From 1c72b14bb984648d3869646cf0657cdc9a129ae7 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:07:05 +0200
Subject: [PATCH 009/262] Disable hooks during EF migration
---
.../Setup/MigrateDatabaseInitializer.cs | 37 ++++++++++---------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs b/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs
index c55b10a240..7042551b5c 100644
--- a/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs
+++ b/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs
@@ -88,28 +88,31 @@ public virtual void InitializeDatabase(TContext context)
}
}
- // run all pending migrations
- var appliedCount = migrator.RunPendingMigrations(context);
-
- if (appliedCount > 0)
- {
- Seed(context);
- }
- else
+ using (new DbContextScope(context as IDbContext, hooksEnabled: false))
{
- // DB is up-to-date and no migration ran.
- EfMappingViewCacheFactory.SetContext(context);
+ // run all pending migrations
+ var appliedCount = migrator.RunPendingMigrations(context);
- if (config is MigrationsConfiguration coreConfig && context is SmartObjectContext)
+ if (appliedCount > 0)
{
- // Call the main Seed method anyway (on every startup),
- // we could have locale resources or settings to add/update.
- coreConfig.SeedDatabase(context as SmartObjectContext);
+ Seed(context);
+ }
+ else
+ {
+ // DB is up-to-date and no migration ran.
+ EfMappingViewCacheFactory.SetContext(context);
+
+ if (config is MigrationsConfiguration coreConfig && context is SmartObjectContext ctx)
+ {
+ // Call the main Seed method anyway (on every startup),
+ // we could have locale resources or settings to add/update.
+ coreConfig.SeedDatabase(ctx);
+ }
}
- }
- // not needed anymore
- this.DataSeeders = null;
+ // not needed anymore
+ this.DataSeeders = null;
+ }
}
#endregion
From b8b3b6ba7376fd5c63f03299e7421ca1cd1d0664 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:26:38 +0200
Subject: [PATCH 010/262] Throw exception when a nested call to
MemoryCache.Get() is made with identical keys to prevent deadlocks.
---
.../Caching/MemoryCacheManager.cs | 18 ++++++++++++++++--
.../Utilities/Threading/KeyedLock.cs | 7 ++++++-
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
index c7e0ba0436..940bd1bda4 100644
--- a/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
+++ b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
@@ -15,6 +15,8 @@ namespace SmartStore.Core.Caching
{
public partial class MemoryCacheManager : DisposableObject, ICacheManager
{
+ const string LockRecursionExceptionMessage = "Acquiring identical cache items recursively is not supported. Key: {0}";
+
// Wwe put a special string into cache if value is null,
// otherwise our 'Contains()' would always return false,
// which is bad if we intentionally wanted to save NULL values.
@@ -79,8 +81,14 @@ public T Get(string key, Func acquirer, TimeSpan? duration = null, bool in
return value;
}
+ var lockKey = "cache:" + key;
+ if (KeyedLock.IsLockHeld(lockKey))
+ {
+ throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
+ }
+
// Get the (semaphore) locker specific to this key
- using (KeyedLock.Lock(key))
+ using (KeyedLock.Lock(lockKey, TimeSpan.FromMinutes(1)))
{
// Atomic operation must be outer locked
if (!TryGet(key, independent, out value))
@@ -104,8 +112,14 @@ public async Task GetAsync(string key, Func> acquirer, TimeSpan? d
return value;
}
+ var lockKey = "cache:" + key;
+ if (KeyedLock.IsLockHeld(lockKey))
+ {
+ throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
+ }
+
// Get the async (semaphore) locker specific to this key
- using (await KeyedLock.LockAsync(key))
+ using (await KeyedLock.LockAsync(lockKey, TimeSpan.FromMinutes(1)))
{
if (!TryGet(key, independent, out value))
{
diff --git a/src/Libraries/SmartStore.Core/Utilities/Threading/KeyedLock.cs b/src/Libraries/SmartStore.Core/Utilities/Threading/KeyedLock.cs
index 4110165632..e08a6deb1c 100644
--- a/src/Libraries/SmartStore.Core/Utilities/Threading/KeyedLock.cs
+++ b/src/Libraries/SmartStore.Core/Utilities/Threading/KeyedLock.cs
@@ -22,7 +22,7 @@ private KeyedLock(object key)
private object Key { get; set; }
private SemaphoreSlim Semaphore { get; set; }
- public bool IsLockHeld
+ public bool HasWaiters
{
get { return _waiterCount > 1; }
}
@@ -38,6 +38,11 @@ public int WaiterCount
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DecrementCount() => Interlocked.Decrement(ref _waiterCount);
+ public static bool IsLockHeld(object key)
+ {
+ return _locks.ContainsKey(key);
+ }
+
public static IDisposable Lock(object key)
{
return Lock(key, _noTimeout);
From 5affd415472bb6ae20530197a8310e5d1c664540 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:38:34 +0200
Subject: [PATCH 011/262] Marked JsonPersistAttribute as obsolete
---
.../SmartStore.Core/Configuration/JsonPersistAttribute.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Libraries/SmartStore.Core/Configuration/JsonPersistAttribute.cs b/src/Libraries/SmartStore.Core/Configuration/JsonPersistAttribute.cs
index 1e467280a9..00d96fe9ba 100644
--- a/src/Libraries/SmartStore.Core/Configuration/JsonPersistAttribute.cs
+++ b/src/Libraries/SmartStore.Core/Configuration/JsonPersistAttribute.cs
@@ -11,6 +11,7 @@ namespace SmartStore.Core.Configuration
/// into single properties.
///
[AttributeUsage(AttributeTargets.Class)]
+ [Obsolete]
public class JsonPersistAttribute : Attribute
{
}
From 0396b382e08e2062c818858fc8964b506bf3f286 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:39:54 +0200
Subject: [PATCH 012/262] (Perf) made SettingService reflection code slightly
faster
---
.../Configuration/SettingService.cs | 41 +++++++------------
1 file changed, 15 insertions(+), 26 deletions(-)
diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs
index 56fc8d3bf1..1caeae24d0 100644
--- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs
+++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs
@@ -222,32 +222,33 @@ public ISettings LoadSetting(Type settingType, int storeId = 0)
protected virtual ISettings LoadSettingCore(Type settingType, int storeId = 0)
{
- if (settingType.HasAttribute(true))
- {
- return LoadSettingsJson(settingType, storeId);
- }
-
- var settings = (ISettings)Activator.CreateInstance(settingType);
-
+ var allSettings = GetAllCachedSettings();
+ var instance = (ISettings)Activator.CreateInstance(settingType);
var prefix = settingType.Name;
foreach (var fastProp in FastProperty.GetProperties(settingType).Values)
{
var prop = fastProp.Property;
- // get properties we can read and write to
+ // Get properties we can read and write to
if (!prop.CanWrite)
continue;
- var key = prefix + "." + prop.Name;
- // load by store
- string setting = GetSettingByKey(key, storeId: storeId, loadSharedValueIfNotFound: true);
+ string key = prefix + "." + prop.Name;
+
+ if (!allSettings.TryGetValue(CreateCacheKey(key, storeId), out var cachedSetting) && storeId > 0)
+ {
+ // // Fallback to shared (storeId = 0)
+ allSettings.TryGetValue(CreateCacheKey(key, 0), out cachedSetting);
+ }
+ string setting = cachedSetting?.Value;
+
if (setting == null)
{
if (fastProp.IsSequenceType)
{
- if ((fastProp.GetValue(settings) as IEnumerable) != null)
+ if ((fastProp.GetValue(instance) as IEnumerable) != null)
{
// Instance of IEnumerable<> was already created, most likely in the constructor of the settings concrete class.
// In this case we shouldn't let the EnumerableConverter create a new instance but keep this one.
@@ -292,7 +293,7 @@ protected virtual ISettings LoadSettingCore(Type settingType, int storeId = 0)
object value = converter.ConvertFrom(setting);
// Set property
- fastProp.SetValue(settings, value);
+ fastProp.SetValue(instance, value);
}
catch (Exception ex)
{
@@ -301,7 +302,7 @@ protected virtual ISettings LoadSettingCore(Type settingType, int storeId = 0)
}
}
- return settings;
+ return instance;
}
public virtual void SetSetting(string key, T value, int storeId = 0, bool clearCache = true)
@@ -367,12 +368,6 @@ protected virtual void SaveSettingCore(ISettings settings, int storeId = 0)
var settingType = settings.GetType();
var prefix = settingType.Name;
- if (settingType.HasAttribute(true))
- {
- SaveSettingsJson(settings);
- return;
- }
-
/* We do not clear cache after each setting update.
* This behavior can increase performance because cached settings will not be cleared
* and loaded from database after each update */
@@ -443,12 +438,6 @@ public virtual void DeleteSetting(Setting setting)
{
using (BeginScope())
{
- if (typeof(T).HasAttribute(true))
- {
- DeleteSettingsJson();
- return;
- }
-
var settingsToDelete = new List();
var allSettings = GetAllSettings();
foreach (var prop in typeof(T).GetProperties())
From 97ce2396d3b4342abbe89137fcb1e62324c5dd4e Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:40:10 +0200
Subject: [PATCH 013/262] Minor fix
---
.../Migrations/201905020948354_WidgetTopics.cs | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/Libraries/SmartStore.Data/Migrations/201905020948354_WidgetTopics.cs b/src/Libraries/SmartStore.Data/Migrations/201905020948354_WidgetTopics.cs
index 4bc080d4fc..304479485c 100644
--- a/src/Libraries/SmartStore.Data/Migrations/201905020948354_WidgetTopics.cs
+++ b/src/Libraries/SmartStore.Data/Migrations/201905020948354_WidgetTopics.cs
@@ -24,9 +24,9 @@ public bool RollbackOnFailure
public void Seed(SmartObjectContext context)
{
- using (var scope = new DbContextScope(ctx: context, validateOnSave: false, hooksEnabled: false, autoCommit: false))
- {
- var widgetTopics = new[]
+ using (var scope = new DbContextScope(ctx: context, validateOnSave: false, hooksEnabled: false))
+ {
+ var widgetTopics = new[]
{
"CheckoutAsGuestOrRegister",
"ContactUs",
@@ -36,13 +36,14 @@ public void Seed(SmartObjectContext context)
};
var topics = context.Set().Where(x => widgetTopics.Contains(x.SystemName)).ToList();
- topics.Each(x => {
+ topics.Each(x =>
+ {
x.RenderAsWidget = true;
x.WidgetWrapContent = false;
});
context.SaveChanges();
- }
- }
+ }
+ }
}
}
From 08063398443ea160d188676c8c57ec29ddf8ce61 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:44:17 +0200
Subject: [PATCH 014/262] TrimmedBuffer: check for NULL in ctor
---
.../SmartStore.Core/Collections/TrimmedBuffer.cs | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/Libraries/SmartStore.Core/Collections/TrimmedBuffer.cs b/src/Libraries/SmartStore.Core/Collections/TrimmedBuffer.cs
index ae0edfb907..06449caef6 100644
--- a/src/Libraries/SmartStore.Core/Collections/TrimmedBuffer.cs
+++ b/src/Libraries/SmartStore.Core/Collections/TrimmedBuffer.cs
@@ -10,7 +10,7 @@ public sealed class TrimmedBuffer : ICollection
private readonly List _list;
public TrimmedBuffer(int maxSize)
- : this(Enumerable.Empty(), default(T), maxSize)
+ : this((IEnumerable)null, default(T), maxSize)
{
}
@@ -20,22 +20,21 @@ public TrimmedBuffer(IEnumerable collection, int maxSize)
}
public TrimmedBuffer(string collection, int maxSize)
- : this(collection.Convert>().Distinct(), default(T), maxSize)
+ : this(collection.NullEmpty()?.Convert>()?.Distinct(), default(T), maxSize)
{
}
public TrimmedBuffer(string collection, T newItem, int maxSize)
- : this(collection.Convert>().Distinct(), newItem, maxSize)
+ : this(collection.NullEmpty()?.Convert>()?.Distinct(), newItem, maxSize)
{
}
public TrimmedBuffer(IEnumerable collection, T newItem, int maxSize)
{
- Guard.NotNull(collection, nameof(collection));
Guard.IsPositive(maxSize, nameof(maxSize));
_maxSize = maxSize;
- _list = new List(collection);
+ _list = new List(collection ?? Enumerable.Empty());
if (newItem != null)
{
From e239edca81547ee0151bd2610d9396aa61b93c84 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 00:54:52 +0200
Subject: [PATCH 015/262] No need for fixed width spacers in horizontal menus
---
.../SmartStore.Web/Views/Shared/Menus/Navbar.cshtml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/Presentation/SmartStore.Web/Views/Shared/Menus/Navbar.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/Menus/Navbar.cshtml
index df8d501573..2a1686b796 100644
--- a/src/Presentation/SmartStore.Web/Views/Shared/Menus/Navbar.cshtml
+++ b/src/Presentation/SmartStore.Web/Views/Shared/Menus/Navbar.cshtml
@@ -96,15 +96,15 @@
- @if (hasIcons)
+ @if (item.Icon.HasValue())
{
-
+
}
- else if (hasImages)
+ else if (item.ImageUrl.HasValue())
{
-
+
}
- @itemText
+ @itemText
@if (item.BadgeText.HasValue())
{
From 04b0c57ac8b96c9f8119f0d39639d99b15e6ff22 Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Fri, 3 May 2019 02:45:54 +0200
Subject: [PATCH 016/262] Menu builder: language resources revision
---
.../Migrations/MigrationsConfiguration.cs | 42 +++++++++----------
.../Views/Shared/Menus/LinkList.cshtml | 4 +-
2 files changed, 22 insertions(+), 24 deletions(-)
diff --git a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
index 12986360fa..0817b588f0 100644
--- a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
+++ b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
@@ -729,9 +729,9 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
builder.AddOrUpdate("Admin.ContentManagement.AddMenu", "Add menu", "Menü hinzufügen");
builder.AddOrUpdate("Admin.ContentManagement.EditMenu", "Edit menu", "Menü bearbeiten");
- builder.AddOrUpdate("Admin.ContentManagement.MenuLinks", "Menu links", "Menü Links");
- builder.AddOrUpdate("Admin.ContentManagement.AddMenuItem", "Add menu link", "Menü Link hinzufügen");
- builder.AddOrUpdate("Admin.ContentManagement.EditMenuItem", "Edit menu link", "Menü Link bearbeiten");
+ builder.AddOrUpdate("Admin.ContentManagement.MenuLinks", "Menu items", "Menü Links");
+ builder.AddOrUpdate("Admin.ContentManagement.AddMenuItem", "Add menu item", "Menü Link hinzufügen");
+ builder.AddOrUpdate("Admin.ContentManagement.EditMenuItem", "Edit menu item", "Menü Link bearbeiten");
builder.AddOrUpdate("Admin.ContentManagement.Menus.NoMenuItemsAvailable",
"There are no menu links available.",
@@ -751,7 +751,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
builder.AddOrUpdate("Providers.MenuItems.FriendlyName.Entity", "Internal object or URL", "Internes Objekt oder URL");
builder.AddOrUpdate("Providers.MenuItems.FriendlyName.Route", "Route", "Route");
- builder.AddOrUpdate("Providers.MenuItems.FriendlyName.Catalog", "Categories", "Warengruppen");
+ builder.AddOrUpdate("Providers.MenuItems.FriendlyName.Catalog", "Category tree", "Warengruppenbaum");
builder.AddOrUpdate("Admin.ContentManagement.Menus.RouteName", "Route name", "Name der Route");
builder.AddOrUpdate("Admin.ContentManagement.Menus.RouteValues", "Route values (JSON)", "Route Werte (JSON)");
@@ -799,22 +799,22 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
"Legt das übergeordnete Menüelement fest. Lassen Sie das Feld leer, um ein Menüelement erster Ebene zu erzeugen.");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.LinkTarget",
- "Link target",
- "Link Ziel",
+ "Target",
+ "Ziel",
"Specifies the link target.",
"Legt das Ziel des Links fest.");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.ShortDescription",
"Short description",
"Kurzbeschreibung",
- "Specifies a short description. Used as the title attribute for the menu link.",
- "Legt eine Kurzbeschreibung fest. Wird als Title-Attribut für das Menüelement verwendet.");
+ "Specifies a short description. Used as the 'title' attribute for the menu link.",
+ "Legt eine Kurzbeschreibung fest. Wird als 'title' Attribut für das Menüelement verwendet.");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.PermissionNames",
- "Permission names",
- "Rechtenamen",
- "Specifies right names (comma-separated). The menu item is not displayed for users without the corresponding permission.",
- "Legt Rechtenamen fest (kommagetrennt). Das Menülement wird für Nutzer ohne betreffenden Rechts nicht angezeigt.");
+ "Required permissions",
+ "Erforderliche Rechte",
+ "Specifies access permissions that are required to display the menu item (at least 1 permission must be granted).",
+ "Legt Zugriffsrechte fest, die für die Anzeige des Menüelementes erforderlich sind (mind. 1 Recht muss gewährt sein).");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.Published",
"Published",
@@ -831,8 +831,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.BeginGroup",
"Begin group",
"Gruppe beginnen",
- "For the first menu item, the option causes a heading according to the short description. For subsequent elements, a separator element is inserted above.",
- "Beim ersten Menüelement bewirkt die Option eine Überschrift gemäß der Kurzbeschreibung. Für nachfolgende Elemente wird oberhalb ein Trennelement eingefügt.");
+ "Inserts a separator before the link and optionally a heading (short description).",
+ "Fügt vor den Link ein Trennelement sowie optional eine Überschrift ein (Kurzbeschreibung).");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.ShowExpanded",
"Show expanded",
@@ -841,16 +841,14 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
"Legt fest, ob das Menü anfänglich geöffnet ist, sofern es Kindelemente besitzt.");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.NoFollow",
- "No follow",
- "No follow",
- "Sets the menu link to 'no follow' via HTML attribute.",
- "Legt das Menüelement per HTML-Attribut auf 'no follow' fest.");
+ "nofollow",
+ "nofollow",
+ "Sets the HTML attribute rel='nofollow'.",
+ "Gibt das HTML-Attribut rel='nofollow' aus.");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.NewWindow",
- "New tab",
- "Neues Tab",
- "Specifies that the menu link is to be opened in a new tab.",
- "Legt fest, dass der Menü Link in einem neuen Tab geöffnet werden soll.");
+ "Open in new browser tab",
+ "In neuem Browsertab öffnen");
builder.AddOrUpdate("Admin.ContentManagement.Menus.Item.Icon",
"Icon",
diff --git a/src/Presentation/SmartStore.Web/Views/Shared/Menus/LinkList.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/Menus/LinkList.cshtml
index 21d04cc73a..0d2c754444 100644
--- a/src/Presentation/SmartStore.Web/Views/Shared/Menus/LinkList.cshtml
+++ b/src/Presentation/SmartStore.Web/Views/Shared/Menus/LinkList.cshtml
@@ -32,11 +32,11 @@
{
if (!isFirst)
{
-
+
}
if (itemText.HasValue() && item.Text != "[SKIP]")
{
-
@itemText
+
@itemText
}
isFirst = false;
continue;
From 2c4ecd2825a342cc0a394f1c54f976bc035fa930 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Fri, 3 May 2019 15:14:18 +0200
Subject: [PATCH 017/262] Fixes menu merging (categories and custom items)
doesn't work correctly (in progress)
---
.../UI/Components/Menu/MenuExtensions.cs | 88 ++++---------------
.../Providers/CatalogMenuItemProvider.cs | 13 +--
.../UI/Menus/Providers/IMenuItemProvider.cs | 3 +-
.../Menus/Providers/MenuItemProviderBase.cs | 10 +--
.../Controllers/MenuController.cs | 4 +-
.../Infrastructure/AdminMenu.cs | 2 +-
.../Installation/InstallDataSeeder.cs | 4 +-
7 files changed, 39 insertions(+), 85 deletions(-)
diff --git a/src/Presentation/SmartStore.Web.Framework/UI/Components/Menu/MenuExtensions.cs b/src/Presentation/SmartStore.Web.Framework/UI/Components/Menu/MenuExtensions.cs
index 54076dd7dd..94ae537fc3 100644
--- a/src/Presentation/SmartStore.Web.Framework/UI/Components/Menu/MenuExtensions.cs
+++ b/src/Presentation/SmartStore.Web.Framework/UI/Components/Menu/MenuExtensions.cs
@@ -126,13 +126,11 @@ public static MenuModel CreateModel(this IMenu menu, string template, Controller
/// Origin of the tree.
/// List of menu items.
/// Menu item providers.
- /// Whether to include menu items without existing parent menu item.
/// Tree of menu items.
public static TreeNode
-@using (Html.BeginZoneContent("end"))
-{
-
-}
+
From 6af5b48faddebc4b9ee6bb761d837fc647720151 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Wed, 8 May 2019 11:11:43 +0200
Subject: [PATCH 033/262] Fixes datetime picker always in English (e.g. for
Product.AvailableStartDateTimeUtc) Fixes datetime picker not displayed after
clearing input (produces script error)
---
.../vendors/datetimepicker/js/tempusdominus-bootstrap-4.js | 7 ++++++-
.../Views/Shared/EditorTemplates/DateTime.cshtml | 2 +-
.../Views/Shared/EditorTemplates/Time.cshtml | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/Presentation/SmartStore.Web/Content/vendors/datetimepicker/js/tempusdominus-bootstrap-4.js b/src/Presentation/SmartStore.Web/Content/vendors/datetimepicker/js/tempusdominus-bootstrap-4.js
index 6d29f3b57b..28e0f52c1b 100644
--- a/src/Presentation/SmartStore.Web/Content/vendors/datetimepicker/js/tempusdominus-bootstrap-4.js
+++ b/src/Presentation/SmartStore.Web/Content/vendors/datetimepicker/js/tempusdominus-bootstrap-4.js
@@ -405,7 +405,12 @@ if ((version[0] <= 2 && version[1] < 17) || (version[0] >= 3)) {
if (!targetMoment) {
if (!this._options.allowMultidate || this._dates.length === 1) {
this.unset = true;
- this._dates = [];
+ this._dates = [];
+ // mgesing: begin fix for "Cannot read property 'isSame' of undefined".
+ // See https://github.com/tempusdominus/bootstrap-4/issues/34
+ this._dates[0] = this.getMoment();
+ this._viewDate = this.getMoment().clone();
+ // mgesing: end fix.
this._datesFormatted = [];
} else {
outpValue = this._element.data('date') + ',';
diff --git a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/DateTime.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/DateTime.cshtml
index 963f70a6ff..0699ac40f2 100644
--- a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/DateTime.cshtml
+++ b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/DateTime.cshtml
@@ -65,6 +65,6 @@
\ No newline at end of file
diff --git a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Time.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Time.cshtml
index 339210ee30..8ac7e3e11b 100644
--- a/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Time.cshtml
+++ b/src/Presentation/SmartStore.Web/Views/Shared/EditorTemplates/Time.cshtml
@@ -46,7 +46,7 @@
From f2ded782fca5548e707a79841dfaa0f50cdf1b17 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Wed, 8 May 2019 12:45:12 +0200
Subject: [PATCH 034/262] Resolves #1369 Shopping cart shows "Discount code
applied", although it is not applied due to a lower tier price
---
changelog.md | 3 +-
.../Migrations/MigrationsConfiguration.cs | 4 ++
.../Controllers/ShoppingCartController.cs | 38 +++++++++++++------
3 files changed, 32 insertions(+), 13 deletions(-)
diff --git a/changelog.md b/changelog.md
index bbbac3b776..995579081d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -80,7 +80,7 @@
* #1571 Compare products only shows one specification attribute option
* #1539 Allow signing in with both e-mail and username
* Trusted Shops: Trustbadge won't be displayed in Popups & Iframes anymore
-* #1461 Admin Grid: filter dialog will be displayed entirely even when grid has no data to display
+* #1461 Admin Grid: filter dialog will be displayed entirely even when grid has no data to display
### Bugfixes
* In a multi-store environment, multiple topics with the same system name cannot be resolved reliably.
@@ -129,6 +129,7 @@
* #1475 select boxes must be wrapped on mobile devices if data-select-url is set
* Fixed the redirection to the homepage for pages which are loaded while the application is restarted
* Fixes product feeds expect a different base price formatting.
+* #1369 Shopping cart shows "Discount code applied", although it is not applied due to a lower tier price.
## SmartStore.NET 3.1.5
diff --git a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
index 8bc6db1bfa..b79004d23d 100644
--- a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
+++ b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs
@@ -878,6 +878,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
builder.AddOrUpdate("Common.Advanced",
"Advanced",
"Erweitert");
+
+ builder.AddOrUpdate("ShoppingCart.DiscountCouponCode.NoMoreDiscount",
+ "Further discounts are not possible.",
+ "Eine weitere Rabattierung ist nicht möglich.");
}
}
}
diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs
index fb5dd78984..c9f634bfed 100644
--- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs
+++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs
@@ -1755,37 +1755,51 @@ public ActionResult SaveCartData(ProductVariantQuery query, bool? useRewardPoint
[FormValueRequired("applydiscountcouponcode")]
public ActionResult ApplyDiscountCoupon(string discountcouponcode, ProductVariantQuery query)
{
- var cart = _workContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id);
+ var model = new ShoppingCartModel();
+ model.DiscountBox.IsWarning = true;
- ParseAndSaveCheckoutAttributes(cart, query);
+ var customer = _workContext.CurrentCustomer;
+ var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id);
- var model = new ShoppingCartModel();
- model.DiscountBox.IsWarning = true;
+ ParseAndSaveCheckoutAttributes(cart, query);
- if (!String.IsNullOrWhiteSpace(discountcouponcode))
+ if (discountcouponcode.HasValue())
{
var discount = _discountService.GetDiscountByCouponCode(discountcouponcode);
var isDiscountValid =
discount != null &&
discount.RequiresCouponCode &&
- _discountService.IsDiscountValid(discount, _workContext.CurrentCustomer, discountcouponcode);
+ _discountService.IsDiscountValid(discount, customer, discountcouponcode);
if (isDiscountValid)
{
- _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.DiscountCouponCode, discountcouponcode);
+ var oldCartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;
- model.DiscountBox.Message = T("ShoppingCart.DiscountCouponCode.Applied");
- model.DiscountBox.IsWarning = false;
- }
+ _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DiscountCouponCode, discountcouponcode);
+
+ var newCartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;
+
+ if (oldCartTotal != newCartTotal)
+ {
+ model.DiscountBox.Message = T("ShoppingCart.DiscountCouponCode.Applied");
+ model.DiscountBox.IsWarning = false;
+ }
+ else
+ {
+ model.DiscountBox.Message = T("ShoppingCart.DiscountCouponCode.NoMoreDiscount");
+
+ _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DiscountCouponCode, null);
+ }
+ }
else
{
model.DiscountBox.Message = T("ShoppingCart.DiscountCouponCode.WrongDiscount");
- }
+ }
}
else
{
model.DiscountBox.Message = T("ShoppingCart.DiscountCouponCode.WrongDiscount");
- }
+ }
PrepareShoppingCartModel(model, cart);
return View(model);
From a544f0a2ba19e1edc5f1a5e8d1692a82611e6a5d Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Wed, 8 May 2019 14:06:47 +0200
Subject: [PATCH 035/262] Typo
---
.../{AddressPeristenceTests.cs => AddressPersistenceTests.cs} | 4 ++--
src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
rename src/Tests/SmartStore.Data.Tests/Common/{AddressPeristenceTests.cs => AddressPersistenceTests.cs} (98%)
diff --git a/src/Tests/SmartStore.Data.Tests/Common/AddressPeristenceTests.cs b/src/Tests/SmartStore.Data.Tests/Common/AddressPersistenceTests.cs
similarity index 98%
rename from src/Tests/SmartStore.Data.Tests/Common/AddressPeristenceTests.cs
rename to src/Tests/SmartStore.Data.Tests/Common/AddressPersistenceTests.cs
index 6046c26a5b..e8b902ba86 100644
--- a/src/Tests/SmartStore.Data.Tests/Common/AddressPeristenceTests.cs
+++ b/src/Tests/SmartStore.Data.Tests/Common/AddressPersistenceTests.cs
@@ -1,13 +1,13 @@
using System;
+using NUnit.Framework;
using SmartStore.Core.Domain.Common;
using SmartStore.Core.Domain.Directory;
using SmartStore.Tests;
-using NUnit.Framework;
namespace SmartStore.Data.Tests.Common
{
[TestFixture]
- public class AddressPeristenceTests : PersistenceTest
+ public class AddressPersistenceTests : PersistenceTest
{
[Test]
public void Can_save_and_load_address()
diff --git a/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj b/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj
index 2c287cbc09..8a35ceb469 100644
--- a/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj
+++ b/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj
@@ -94,7 +94,7 @@
-
+
From 52323a3d8c1772afd948f3e6f60ab778c4e7dc72 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Wed, 8 May 2019 16:08:17 +0200
Subject: [PATCH 036/262] Fixes permission names applied on menu items had no
effect
---
.../SmartStore.Web.Framework/UI/Menus/DatabaseMenu.cs | 2 +-
src/Presentation/SmartStore.Web.Framework/UI/Menus/MenuBase.cs | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/Presentation/SmartStore.Web.Framework/UI/Menus/DatabaseMenu.cs b/src/Presentation/SmartStore.Web.Framework/UI/Menus/DatabaseMenu.cs
index b5f35a87a0..3722376973 100644
--- a/src/Presentation/SmartStore.Web.Framework/UI/Menus/DatabaseMenu.cs
+++ b/src/Presentation/SmartStore.Web.Framework/UI/Menus/DatabaseMenu.cs
@@ -67,7 +67,7 @@ public DatabaseMenu(
public override string Name { get; }
- public override bool ApplyPermissions => false;
+ public override bool ApplyPermissions => true;
public override void ResolveElementCounts(TreeNode curNode, bool deep = false)
{
diff --git a/src/Presentation/SmartStore.Web.Framework/UI/Menus/MenuBase.cs b/src/Presentation/SmartStore.Web.Framework/UI/Menus/MenuBase.cs
index ebe4927312..0ff44e23bb 100644
--- a/src/Presentation/SmartStore.Web.Framework/UI/Menus/MenuBase.cs
+++ b/src/Presentation/SmartStore.Web.Framework/UI/Menus/MenuBase.cs
@@ -59,7 +59,8 @@ public TreeNode Root
protected virtual void DoApplyPermissions(TreeNode root)
{
// Hide based on permissions
- root.Traverse(x => {
+ root.Traverse(x =>
+ {
if (!MenuItemAccessPermitted(x.Value))
{
x.Value.Visible = false;
From 7a07ea14340dbbec151e625139988a9ac325a197 Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Wed, 8 May 2019 18:28:58 +0200
Subject: [PATCH 037/262] Fixes a unit test
---
.../Configuration/ConfigFileSettingService.cs | 50 +++++++++++++++----
.../ConfigurationProviderTests.cs | 6 +--
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/src/Tests/SmartStore.Services.Tests/Configuration/ConfigFileSettingService.cs b/src/Tests/SmartStore.Services.Tests/Configuration/ConfigFileSettingService.cs
index 710a3247c8..d7c1e36d24 100644
--- a/src/Tests/SmartStore.Services.Tests/Configuration/ConfigFileSettingService.cs
+++ b/src/Tests/SmartStore.Services.Tests/Configuration/ConfigFileSettingService.cs
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;
using System.Configuration;
+using System.Globalization;
using System.Linq;
+using SmartStore.ComponentModel;
using SmartStore.Core.Caching;
+using SmartStore.Core.Configuration;
using SmartStore.Core.Data;
using SmartStore.Core.Domain.Configuration;
using SmartStore.Services.Configuration;
namespace SmartStore.Services.Tests.Configuration
{
- public class ConfigFileSettingService : SettingService
+ public class ConfigFileSettingService : SettingService
{
public ConfigFileSettingService(
ICacheManager cacheManager,
@@ -20,13 +23,15 @@ public ConfigFileSettingService(
public override Setting GetSettingById(int settingId)
{
- throw new InvalidOperationException("Get setting by id is not supported");
+ throw new InvalidOperationException("Get setting by id is not supported.");
}
public override T GetSettingByKey(string key, T defaultValue = default(T), int storeId = 0, bool loadSharedValueIfNotFound = false)
{
- if (String.IsNullOrEmpty(key))
- return defaultValue;
+ if (string.IsNullOrEmpty(key))
+ {
+ return defaultValue;
+ }
var settings = GetAllSettings();
key = key.Trim().ToLowerInvariant();
@@ -34,22 +39,24 @@ public override Setting GetSettingById(int settingId)
var setting = settings.FirstOrDefault(x => x.Name.Equals(key, StringComparison.InvariantCultureIgnoreCase) &&
x.StoreId == storeId);
- //load shared value?
+ // Load shared value?
if (setting == null && storeId > 0 && loadSharedValueIfNotFound)
{
setting = settings.FirstOrDefault(x => x.Name.Equals(key, StringComparison.InvariantCultureIgnoreCase) &&
x.StoreId == 0);
}
- if (setting != null)
- return setting.Value.Convert();
+ if (setting != null)
+ {
+ return setting.Value.Convert();
+ }
return defaultValue;
}
public override void DeleteSetting(Setting setting)
{
- throw new InvalidOperationException("Deleting settings is not supported");
+ throw new InvalidOperationException("Deleting settings is not supported.");
}
public override void SetSetting(string key, T value, int storeId = 0, bool clearCache = true)
@@ -57,13 +64,36 @@ public override void SetSetting(string key, T value, int storeId = 0, bool cl
throw new NotImplementedException();
}
- public override IList GetAllSettings()
+ protected override ISettings LoadSettingCore(Type settingType, int storeId = 0)
+ {
+ var appSettings = ConfigurationManager.AppSettings;
+ var result = Activator.CreateInstance(settingType);
+
+ var properties = FastProperty.GetCandidateProperties(settingType)
+ .Select(pi => FastProperty.GetProperty(pi, PropertyCachingStrategy.Uncached))
+ .Where(pi => pi.IsPublicSettable);
+
+ foreach (var prop in properties)
+ {
+ var key = string.Concat(settingType.Name, ".", prop.Name);
+ if (appSettings.AllKeys.Contains(key))
+ {
+ var val = appSettings.Get(key);
+ var convertedVal = val.Convert(prop.Property.PropertyType, CultureInfo.CurrentCulture);
+ prop.SetValue(result, convertedVal);
+ }
+ }
+
+ return result as ISettings;
+ }
+
+ public override IList GetAllSettings()
{
var settings = new List();
var appSettings = ConfigurationManager.AppSettings;
foreach (var setting in appSettings.AllKeys)
{
- settings.Add(new Setting()
+ settings.Add(new Setting
{
Name = setting.ToLowerInvariant(),
Value = appSettings[setting]
diff --git a/src/Tests/SmartStore.Services.Tests/Configuration/ConfigurationProviderTests.cs b/src/Tests/SmartStore.Services.Tests/Configuration/ConfigurationProviderTests.cs
index af51bc827f..bfd1a7aefb 100644
--- a/src/Tests/SmartStore.Services.Tests/Configuration/ConfigurationProviderTests.cs
+++ b/src/Tests/SmartStore.Services.Tests/Configuration/ConfigurationProviderTests.cs
@@ -1,7 +1,7 @@
-using SmartStore.Core.Configuration;
+using NUnit.Framework;
+using SmartStore.Core.Configuration;
using SmartStore.Services.Configuration;
using SmartStore.Tests;
-using NUnit.Framework;
namespace SmartStore.Services.Tests.Configuration
{
@@ -19,7 +19,7 @@ public class ConfigurationProviderTests : ServiceTest
[Test]
public void Can_get_settings()
{
- // requires settings to be set in app.config in format TestSettings.[PropertyName]
+ // Requires settings to be set in app.config in format TestSettings.[PropertyName].
var settings = _settingService.LoadSetting();
settings.ServerName.ShouldEqual("Ruby");
settings.Ip.ShouldEqual("192.168.0.1");
From 6f38b65dffc836eb86b6e56a3adbe1d1a1cbeced Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Thu, 9 May 2019 09:41:57 +0200
Subject: [PATCH 038/262] Resolves #1623 LinkResolver creates duplicate cache
entries
---
src/Libraries/SmartStore.Services/Cms/LinkResolver.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Libraries/SmartStore.Services/Cms/LinkResolver.cs b/src/Libraries/SmartStore.Services/Cms/LinkResolver.cs
index 5320cba347..b541e73ed4 100644
--- a/src/Libraries/SmartStore.Services/Cms/LinkResolver.cs
+++ b/src/Libraries/SmartStore.Services/Cms/LinkResolver.cs
@@ -97,7 +97,7 @@ public virtual LinkResolverResult Resolve(string linkExpression, IEnumerable x.Active).Select(x => x.Id)));
From 3fd486a16d7598c86cb77bcd66ab3e20a67750fe Mon Sep 17 00:00:00 2001
From: Marcus Gesing
Date: Thu, 9 May 2019 14:21:30 +0200
Subject: [PATCH 039/262] Import: Fixes cannot convert object of type
"SmartStore.Services.DataExchange.Import.ImportResult" to type
"SmartStore.Services.DataExchange.Import.SerializableImportResult"
---
.../DataExchange/Import/ImportResult.cs | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs
index 8c5983753d..a0de84eae2 100644
--- a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs
+++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs
@@ -176,8 +176,21 @@ object ICloneable.Clone()
public SerializableImportResult Clone()
{
- return (SerializableImportResult)this.MemberwiseClone();
- }
+ var result = new SerializableImportResult();
+ result.StartDateUtc = StartDateUtc;
+ result.EndDateUtc = EndDateUtc;
+ result.TotalRecords = TotalRecords;
+ result.SkippedRecords = SkippedRecords;
+ result.NewRecords = NewRecords;
+ result.ModifiedRecords = ModifiedRecords;
+ result.AffectedRecords = AffectedRecords;
+ result.Cancelled = Cancelled;
+ result.Warnings = Warnings;
+ result.Errors = Errors;
+ result.LastError = LastError;
+
+ return result;
+ }
}
From de4065ac4655d6bec3aa9c6555af0931f4cf34ba Mon Sep 17 00:00:00 2001
From: Murat Cakir
Date: Thu, 9 May 2019 21:25:58 +0200
Subject: [PATCH 040/262] Small fix in IconChooser script
---
.../Administration/Scripts/smartstore.iconchooser.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.iconchooser.js b/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.iconchooser.js
index 5ce1cf82b0..26e5388c0a 100644
--- a/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.iconchooser.js
+++ b/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.iconchooser.js
@@ -3,6 +3,13 @@ $(function () {
var map = {};
$(select).data('icons', map);
+ // Add icon data of selected icon (intial option) to the map very early
+ var selectedOption = $(select).find('option[data-icon][selected]');
+ if (selectedOption.length) {
+ var icon = selectedOption.data('icon');
+ map[icon.id] = icon;
+ }
+
$(select).select2({
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
minimumInputLength: 0,
From 78dc5f28a024968bb848c60cc03d5a7bd844daf8 Mon Sep 17 00:00:00 2001
From: Michael Herzog
Date: Fri, 10 May 2019 12:43:06 +0200
Subject: [PATCH 041/262] If artlist is boxed the price line also needs two
lines
---
.../SmartStore.Web/Themes/Flex/Content/_artlist.scss | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Presentation/SmartStore.Web/Themes/Flex/Content/_artlist.scss b/src/Presentation/SmartStore.Web/Themes/Flex/Content/_artlist.scss
index dc3f62b1d4..e28880a4b8 100644
--- a/src/Presentation/SmartStore.Web/Themes/Flex/Content/_artlist.scss
+++ b/src/Presentation/SmartStore.Web/Themes/Flex/Content/_artlist.scss
@@ -589,6 +589,11 @@ $art-border-color: #ddd;
// At least 2 lines height for description
height: ($art-font-size-sm * $art-line-height) * 2;
}
+
+ &.artlist-boxed .art-price-block {
+ // At least 2 lines height for description
+ height: ($art-font-size-sm * $art-line-height) * 2;
+ }
.art-delivery-info,
.art-pangv {
From fec8b06ee6d838c63f139d8619aa3060c4ea6048 Mon Sep 17 00:00:00 2001
From: Zihni Artar
Date: Fri, 10 May 2019 15:22:15 +0200
Subject: [PATCH 042/262] Installation: Updated some language resources
---
.../Setup/SeedData/InvariantSeedData.cs | 34 +++++++++---------
.../App_Data/Samples/company_logo.png | Bin 5224 -> 1975 bytes
.../Installation/DeDESeedData.cs | 18 +++++-----
src/Presentation/SmartStore.Web/favicon.ico | Bin 9158 -> 34494 bytes
4 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs
index fe8e4280be..00adad3721 100644
--- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs
+++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs
@@ -8909,7 +8909,7 @@ public IList CategoriesFirstLevel()
Name = "Apple",
Alias = "Apple",
CategoryTemplateId = categoryTemplateInGridAndLines.Id,
- Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_apple.png"), "image/jpeg", GetSeName("Apple")),
+ Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_apple.png"), "image/png", GetSeName("Apple")),
Published = true,
DisplayOrder = 1,
MetaTitle = "Apple",
@@ -13213,7 +13213,7 @@ public IList BlogPosts()
Language = defaultLanguage,
Title = "Customer Service - Client Service",
Body = "
Managing online business requires different skills and abilities than managing a business in the ‘real world.’ Customers can easily detect the size and determine the prestige of a business when they have the ability to walk in and take a look around. Not only do ‘real-world’ furnishings and location tell the customer what level of professionalism to expect, but "real world" personal encounters allow first impressions to be determined by how the business approaches its customer service. When a customer walks into a retail business just about anywhere in the world, that customer expects prompt and personal service, especially with regards to questions that they may have about products they wish to purchase.
Customer service or the client service is the service provided to the customer for his satisfaction during and after the purchase. It is necessary to every business organization to understand the customer needs for value added service. So customer data collection is essential. For this, a good customer service is important. The easiest way to lose a client is because of the poor customer service. The importance of customer service changes by product, industry and customer. Client service is an important part of every business organization. Each organization is different in its attitude towards customer service. Customer service requires a superior quality service through a careful design and execution of a series of activities which include people, technology and processes. Good customer service starts with the design and communication between the company and the staff.
In some ways, the lack of a physical business location allows the online business some leeway that their ‘real world’ counterparts do not enjoy. Location is not important, furnishings are not an issue, and most of the visual first impression is made through the professional design of the business website.
However, one thing still remains true. Customers will make their first impressions on the customer service they encounter. Unfortunately, in online business there is no opportunity for front- line staff to make a good impression. Every interaction the customer has with the website will be their primary means of making their first impression towards the business and its client service. Good customer service in any online business is a direct result of good website design and planning.
By Jayashree Pakhare (buzzle.com)
",
- Tags = "e-commerce, SmartStore.NET, asp.net, sample tag, money",
+ Tags = "e-commerce, Smartstore.NET, asp.net, sample tag, money",
CreatedOnUtc = DateTime.UtcNow.AddSeconds(1),
};
@@ -13233,26 +13233,26 @@ public IList NewsItems()
{
AllowComments = true,
Language = defaultLanguage,
- Title = "SmartStore.NET new release!",
- Short = "SmartStore.NET includes everything you need to begin your e-commerce online store.",
- Full = "
SmartStore.NET includes everything you need to begin your e-commerce online store. We have thought of everything and it's all included!
From downloads to documentation, www.smartstore.com offers a comprehensive base of information, resources, and support to the SmartStore.NET community.
",
+ Title = "Smartstore.NET 3.2 now with the new CMS Page Builder",
+ Short = "Create fascinating content with the new Page Builder",
+ Full = "
Create fascinating content from products, product groups, images, videos and texts. Transitions, animations, gradients, hover effects or overlays are easily applied in the WYSIWYG editor.
More information about Smartstore 3.2 and Page Builder can be found at www.smartstore.com
",
Published = true,
- MetaTitle = "SmartStore.NET new release!",
+ MetaTitle = "Smartstore.NET 3.2",
CreatedOnUtc = DateTime.Now
};
var news2 = new NewsItem()
- {
- AllowComments = true,
- Language = defaultLanguage,
- Title = "New online store is open!",
- Short = "The new SmartStore.NET store is open now! We are very excited to offer our new range of products. We will be constantly adding to our range so please register on our site, this will enable you to keep up to date with any new products.",
- Full = "
Our online store is officially up and running. Stock up for the holiday season! We have a great selection of items. We will be constantly adding to our range so please register on our site, this will enable you to keep up to date with any new products.
All shipping is worldwide and will leave the same day an order is placed! Happy Shopping and spread the word!!
",
- Published = true,
- MetaTitle = "New online store is open!",
- CreatedOnUtc = DateTime.Now
- };
+ {
+ AllowComments = true,
+ Language = defaultLanguage,
+ Title = "Smartstore.NET new release!",
+ Short = "Smartstore.NET includes everything you need to begin your e-commerce online store.",
+ Full = "
Smartstore.NET includes everything you need to begin your e-commerce online store. We have thought of everything and it's all included!
From downloads to documentation, www.smartstore.com offers a comprehensive base of information, resources, and support to the Smartstore.NET community.
",
+ Published = true,
+ MetaTitle = "Smartstore.NET new release!",
+ CreatedOnUtc = DateTime.Now
+ };
- var entities = new List
+ var entities = new List
{
news1, news2
};
diff --git a/src/Presentation/SmartStore.Web/App_Data/Samples/company_logo.png b/src/Presentation/SmartStore.Web/App_Data/Samples/company_logo.png
index e21a12ae34e763c836d4e7bfa2738bba7f010cea..6aedbcf1b67fcbf2f4f307930d55414b96583460 100644
GIT binary patch
literal 1975
zcmV;o2T1sdP)Px#32;bRa{vGi!vFvd!vV){sAK>D0Blf9R7FQ{OaK4?
z0000000000000000000000000000>o00000000000000000000002p}kpKVyP@}9V
zb-^xpyHdEM{HrW4c)eo4#V>ii_^2^Nv4cdggh#ZF_op)e001v}y+pBuW5LGvs580_
zZ>sh^xC}3UX?>o9awUBN!8h)&cf%Xqm&BjI1onBVo8={2}4LXNq5|I-v1p(yGq6eGMSS(C%FE^Afx5Fmap8|?KazN
zv(5gn^@rp6e119ZzJB}h^|0|sRF3DDk6;eWPiJ2@Ce99D5|s+(=Z_5w#8Sa*WR4IE
z0Q2n8bpH5Q0rTyt!)VS0fO%$@IlO#qU>@V*!F)@$45mk&wb+oq8O#C~2j;e!VTv}G
zr^&mIfT2@0&3<U9A5yoog^nM~U=Hu^r~S&FY#<_K_(%LMm|jUatgK{&
z5Z#{v(+Pbq!2~e-i?g@WQoBTA3~^367g4{x?_NxkS_3ov2MauAcpB~oQUT-9EIUko
z#76gjC78p<9Wa;6`<2u9#5=B?a`7^LUPGuHn3YM!YcT!oCvju=dI)~gf;ry@bNPN)
z0Mpj#zQfqq8NuklfcM`iD-YH)LPR%2_))w>Cfi8
zKTN8%$>K?BYooXv6PPfM1H;3r*mQJi6O#jjClQ4xl9Ab1yo#%oTVRe^jiecvxyz8q
zL1Es2ksehS5n&cHXG}&|MT$1LOmY)C^6YL|(j;=dQ6xKOR}0ic!-}Iw`iX#fXc3$K
zN1}&dq##9_`Vm(Mi%+3cNg$ZxqhMw(v*XFDrR4z3n2T>tLArd&DnP$61jC)xa_ui=
znsV2I3C!|of_LBy2Ir{CT9cMsk-$u*rU5^{$*aU#Lg!%4kAk`E=YFB&fT6W!
zrE^-iC8zv}cQv0%&@?+`)-gj(tTQmE5!v2-R05;Roz^!OoHN{12R?x#kHLrOq_65U
z1oQGRm<5@KXiStQgF#m{3zuVs+8FQm&k9YT;zKYYUSut*6$~!5srV(2U{LWADWb{d
zUJfatu&&E1*d}wCFT~xy1M|Kln7GXc4I#oR7&HT8K*7jhil&2LQX5v9_6mkJ-j`M(
zHJj+EH44F)77P>Zy;oq4U)Jm}1M_`ZOO7el=U_++CY5XVECCq02&U)@%^w6a)F70=
znot_Az|anuS?HBk?IAE>7~9t1sJ=-_F=1K5
ztFcz#HDFvI;(JZx{B54IUjdUI*=;biV8~VH7MPH}a?z?_Ol44O5CCJZIbAx+O4v$r5)Q=jf!%U`~b0=j#kilVW&V?C|a$
zn5a*cYRfgfnvg{q)W`CO@2a<1S4VC(<%2rO%Ma
z4cJC1s+2mjo*qh`HCkl9XE>sfdd%IdlmIYE+Y<5R0g5luxex%1$o=G)B;nBY<&Bnt
ziupd6xBbGOJdhVgC0p_O7ZBgC^z+N!-EMgKOG)1djc|i&q|#I)oH$HFNWQrzrt3yt
ze>IyYYzwh6+Q-fHV4Yfyu2*uqV80Mb``vRJOun!sI6XNRSgudCD!o0szj#fzAn;Dx
ze^B&3^B&?Tw*+tBH!Q_zPN)4L^-cSIzX927v&}Z!Y_tE@{sGmcI|7LTrQ!ep002ov
JPDHLkV1hyim%IP~
literal 5224
zcmb`Lbx;&uyT^&8o25&T29fR*QN&%kI~FNX1f)}>k&qNtKw7$cK^n;w>DZ+^mJWs8
z%iQ0cJNKXWy>n;oGxMDDJ>NOcXP%j7&OawcM@yZIn28t*3yVzSg__>|es!M;gt+%>
ze9#gd78cH(4%pz?{Skw~DF43(27~^G_piwR%KyK1anJcD?hDaq^u4|p|7HEB{>S`p
z=iiI}S^MvA-edn4^3}{eO-fus?6HWXsF;ePJbF7Ez2S>qb5(z;ir!5?Zv~;(JyxUX
z)Sf6~PJf{HQkOq6U=FfXl@*r)n9#>f$PmT_AC`F!*85J-r#)y?rINhdWeb6NRPe=ou;DM~{z+$WE(>&+CbV_yyPFXwj3r2j9ps
zw`N4Nx+>Jy7Bq{O!XrvK(UJ*SbvYkqeUUjrFH!#xE
z!ko6F7u5g4RWWy$ex6QfgvA?(c6XIisK2Af8(UXL%RhZ|n4@y^cFfgEU`e*m<>H&<
z4|eDk>%U_ncf+LpEfFyv-e$(THsxCMX6dGfXkQE{>{kk)&wDR+>Y6H|mPbFL=6qwr
zeUJk#wOK9)6V78*=1cX4Rz@1=30BPY66R_KeL1x;l~kM?HQMf#oAw@JWA!}-ywe35
zN|T+=lle2qbzDKavseu8O`Gfqy;=4wNVN|0&_k9B&nF3-H1cnJqQP8FU2WwaBR+SQ
zdcJqnU(VvfT+LROCL=kry6zu<=X*UZeXM$1{M!qfAtLNU8U*%c=KIqPcoCz#LJuB#0tIczBb
zt^6MAYc!MoS)R?s6JL`bt*($9;^r(y@5#e$|dw(|J8oDvAbM^HB{i0o{{-Qj4Uc)L7xC!@zz%fyX1uXe7I
z-&O~35TO`;txT!(IK+SA`pKOIDU*@J9n!s-60LciG?7A#+MSIHAm#6{v;-1yzcSOiL&J{
z*0aAl-C1>Jku~nGksp{y<-#LAy`I>LeRv;wS(tzWQMvS(gsvM`d)R;5h
z;_aRk*
zFZ86X-yYq%?EaR<>?xdW>QTfkZZ~bPpLF|BN-K-=kcGX-(bq-jURFS7$*av8A-na~
z!3{2lf8qX_vo!(wbWA-o2+gH~@a+OoKcoJ-;@0Un1k7;W