Skip to content

Update fork #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Oct 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
ab134ce
More work on PageBlocks (Storytelling)
muratcakir Sep 22, 2018
60d231e
Added a string resource
mgesing Sep 24, 2018
7041627
Forum: Further limited to store checks necessary
mgesing Sep 24, 2018
77470a2
Merge pull request #1503 from rhinterndorfer/3.x
muratcakir Sep 24, 2018
a2d0975
Admin theme: css grid layout & colors
muratcakir Sep 24, 2018
8039e3f
Theming: various css enhancements
muratcakir Sep 25, 2018
522ec88
Resolves #417 Restrict forum groups to specific customer roles
mgesing Sep 25, 2018
db1dfb8
Integrate ACL of forum groups in forum search
mgesing Sep 25, 2018
d3f80fe
Please execute "update-database -TargetMigration NewsletterSubscripti…
mgesing Sep 25, 2018
8ba06cf
Stated with published property of forum topic and forum post
mgesing Sep 25, 2018
dd6c3de
More work on Storytelling feature
muratcakir Sep 26, 2018
aedfad7
Please execute "update-database -TargetMigration NewsletterSubscripti…
mgesing Sep 26, 2018
a2e8063
More on published property of forum topic and forum post
mgesing Sep 26, 2018
56ad33c
Closes #1499 Add hint to forms indicating that fields with an asteris…
Michael-Herzog Sep 26, 2018
22dcc76
More on published property of forum topic and forum post
mgesing Sep 26, 2018
7924067
Implemented FastInvoker for speeding up dynamic method invocation
muratcakir Sep 26, 2018
9668c0a
CSS enhancements in admin theme
muratcakir Sep 27, 2018
4df91fd
Removed default avatar setting (obsolete)
mgesing Sep 27, 2018
4445e93
Integrate published property of forum topics and posts in forum search
mgesing Sep 27, 2018
75cfe5c
Several performance improvements at forum service
mgesing Sep 27, 2018
00a3573
Published property and updating forum counter
mgesing Sep 27, 2018
389a7ce
Fix for HtmlHelper.BeginZoneContent(): capture inner writers also (Ht…
muratcakir Sep 28, 2018
124dd9b
CSS option class to skip fixing the top section header (backend)
muratcakir Sep 28, 2018
f1a399e
Small variant of numeric textbox
muratcakir Sep 28, 2018
ee5d99d
Do not allow to unpublish first post of a forum topic. Unpublish topi…
mgesing Sep 28, 2018
6adb4db
Resolves forum paging issue
mgesing Sep 28, 2018
260d02e
Improved forum selection box when moving a topic
mgesing Sep 28, 2018
904f60c
Improved asynchronous loading of forum search hits
mgesing Sep 28, 2018
0b33722
Minor code fix
muratcakir Sep 29, 2018
efe8fe2
Import: Validate picture parameter modifies file size thus subsequent…
Michael-Herzog Oct 1, 2018
95499de
Avoid "No route in the route table matches the supplied values" (rare…
mgesing Oct 1, 2018
80d70fe
Avoid exception "Failed to parse email address for variable..." if pa…
mgesing Oct 1, 2018
141c665
Added CustomerLoggedInEvent
Michael-Herzog Oct 1, 2018
c9fc0ea
Updated changelog
Michael-Herzog Oct 1, 2018
680c217
Updated changelog
Michael-Herzog Oct 1, 2018
9e88ffb
Getting started with voting on forum posts
mgesing Oct 1, 2018
7c836ab
Added object-fit css util classes
muratcakir Oct 2, 2018
b9307ca
Fixes region cannot be selected in checkout when entering a billing o…
mgesing Oct 2, 2018
4743fd6
Updated change log
mgesing Oct 2, 2018
2490088
More on forum post voting
mgesing Oct 2, 2018
73d14c2
Fixed typos
mgesing Oct 2, 2018
9f26066
Fixed non-localized strings
mgesing Oct 2, 2018
d487e6f
Votes of forum posts are customer content thus subject to GDPR
mgesing Oct 2, 2018
233fbcf
Resolves #1517 Creating a manufacturer throws an exception
mgesing Oct 2, 2018
94cf628
Code convention
muratcakir Oct 2, 2018
4c27834
Minor refactoring
muratcakir Oct 3, 2018
512fd4c
SQL CE: Fixes SqlCeException in CatalogSearchQueryAliasMapper. Resolv…
mgesing Oct 3, 2018
daf9a9c
SQL CE: DropIndex fails during installation
mgesing Oct 3, 2018
b72df74
More on SqlCeException in CatalogSearchQueryAliasMapper fix
mgesing Oct 4, 2018
80d528e
Resolves #1515 Poll: Add result tab with a list of answers and custom…
mgesing Oct 4, 2018
32e1e28
Minor improvements
mgesing Oct 4, 2018
0b52c83
Added wow script to SmartStore.Web
Michael-Herzog Oct 5, 2018
dfd33f8
Resolves #1510 Breadcrumb of an associated product should include the…
mgesing Oct 5, 2018
14a1c4b
Minor theming stuff
muratcakir Oct 6, 2018
6adbcae
Resolves #1518 Allow for blank salutation and country in company sett…
mgesing Oct 7, 2018
fa7606c
Resolves #909 Email & Phone number should be optional fields for Addr…
mgesing Oct 8, 2018
3734b2d
#425 Updates two unclear string resources
mgesing Oct 8, 2018
eb922b0
More on "Breadcrumb of an associated product should include the group…
mgesing Oct 8, 2018
652cf16
Removed an unused private method
mgesing Oct 9, 2018
e59f7e4
Storytelling (wip)
muratcakir Oct 10, 2018
ba131a7
Dialog to create an import profile was out of function
mgesing Oct 11, 2018
48996e3
min, max, step params for numeric textbox editor
muratcakir Oct 12, 2018
456887d
New EditorTemplate "Range"
muratcakir Oct 12, 2018
dda751d
Compact version of FileUploader component
muratcakir Oct 12, 2018
b6e437f
Backend theming: made buttons slightly rounded
muratcakir Oct 12, 2018
c0b973d
Color opacity mode for new Range editor
muratcakir Oct 12, 2018
849efdf
AdminControllerBase now takes new "NonAdminAttribute" into account be…
muratcakir Oct 12, 2018
eb909bd
"nowidgets" query bypasses rendering of request scoped widgets (requi…
muratcakir Oct 12, 2018
2288225
(perf) prevent libSass file globbing mess (checking files again and a…
muratcakir Oct 12, 2018
027a554
Minor refactoring in block interfaces
muratcakir Oct 12, 2018
f506c11
Fixed EfDbCache mem leak (hopefully)
muratcakir Oct 12, 2018
9500276
Redesigned file uploader component
muratcakir Oct 13, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
## SmartStore.NET 3.2

### New Features
* **EmailReminder**:
* Reminders for open shopping carts
* Reminders for product reviews
* Reminders to visit the shop after a long absence
* #1144 Enable multi server search index
* Made Topic ACL enabled
* Implemented paging & filtering for Topic grid
Expand All @@ -15,18 +19,31 @@
* Added option to display preview pictures in product lists
* Added option to add multiple file versions to product download section
* Added options for alternating price display (in badges)
* Added option to display a captcha on forum pages when creating or replying to a topic.
* **Forum**:
* Added option to display a captcha on forum pages when creating or replying to a topic.
* #417 Restrict forum groups to specific customer roles.
* Added published property to forum topic and post.
* Added voting for forum posts.
* Several performance improvements.
* **MegaSearch**:
* Supports searching for forum posts.
* #1172 Option to display related search terms on search page.
* Customer avatar: Letter with colored background if no avatar image was uploaded.
* Viveum: Supports payment via "Virtual Account Brands" like PayPal.
* Added options for alternating price display (in badges).
* #1515 Poll: Add result tab with a list of answers and customers for a poll

### Improvements
* (Perf) Significantly increased query performance for products with a lot of category assignments (> 10).
* Debitoor: Partially update customer instead of full update to avoid all fields being overwritten
* #1479 Show in messages the delivery time at the time of purchase
* #1184 Sort Current shopping carts & Current wishlists by ShoppingCartItem.CreatedOn.
* #1106 BMECat: import & export support for product keywords
* #1499 Added hint to forms indicating that fields with an asterisk (*)
* Added filter for newsletter subscriber export by working language
* Refactored download section
* Enhanced EntityPicker to pick from customers, manufacturers & categories
* #1510 Breadcrumb of an associated product should include the grouped product if it has no assigned categories.

### Bugfixes
* In a multi-store environment, multiple topics with the same system name cannot be resolved reliably.
Expand Down Expand Up @@ -56,6 +73,11 @@
* Wrong order of featured products on category page.
* #1504 Cart item price calculation wrong if attribute combinations with text types are involved.
* #1485 Dropdown list for product sorting does not work with Internet Explorer 11.
* #1468 Twitter authentication not working anymore.
* Newsletter subscription didn't work when customer privacy setting DisplayGdprConsentOnForms was turned off
* Fixed social media image detection
* Fixed redirection of bots when several languages were active
* Region cannot be selected in checkout when entering a billing or shipping address


## SmartStore.NET 3.1.5
Expand Down
8 changes: 7 additions & 1 deletion src/Libraries/SmartStore.Core/Caching/RequestCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace SmartStore.Core.Caching
{
public class RequestCache : IRequestCache
public class RequestCache : DisposableObject, IRequestCache
{
const string RegionName = "SmartStoreNET:";

Expand Down Expand Up @@ -124,5 +124,11 @@ private string BuildKey(string key)
{
return RegionName + key.EmptyNull();
}

protected override void OnDispose(bool disposing)
{
if (disposing)
Clear();
}
}
}
4 changes: 2 additions & 2 deletions src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public object Activate(params object[] parameters)
return Invoker(parameters);
}

#region Static

/// <summary>
/// Creates a single fast constructor invoker. The result is not cached.
/// </summary>
Expand Down Expand Up @@ -78,8 +80,6 @@ public static Func<object[], object> MakeFastInvoker(ConstructorInfo constructor
return lambda.Compile();
}

#region Static

/// <summary>
/// Creates and caches fast constructor invokers
/// </summary>
Expand Down
228 changes: 228 additions & 0 deletions src/Libraries/SmartStore.Core/ComponentModel/FastInvoker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
using System.Collections.Concurrent;
using SmartStore.Utilities;

namespace SmartStore.ComponentModel
{
public class FastInvoker
{
private static readonly ConcurrentDictionary<MethodKey, FastInvoker> _invokersCache = new ConcurrentDictionary<MethodKey, FastInvoker>();

public FastInvoker(MethodInfo methodInfo)
{
Guard.NotNull(methodInfo, nameof(methodInfo));

Method = methodInfo;
Invoker = MakeFastInvoker(methodInfo);
ParameterTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
}

/// <summary>
/// Gets the backing <see cref="MethodInfo"/>.
/// </summary>
public MethodInfo Method { get; private set; }

/// <summary>
/// Gets the parameter types from the backing <see cref="MethodInfo"/>
/// </summary>
public Type[] ParameterTypes { get; private set; }

/// <summary>
/// Gets the method invoker.
/// </summary>
public Func<object, object[], object> Invoker { get; private set; }

/// <summary>
/// Invokes the method using the specified parameters.
/// </summary>
/// <returns>The method invocation result.</returns>
public object Invoke(object obj, params object[] parameters)
{
return Invoker(obj, parameters);
}

#region Static

/// <summary>
/// Creates a single fast method invoker. The result is not cached.
/// </summary>
/// <param name="method">Method to create invoker for.</param>
/// <returns>The fast method invoker delegate.</returns>
public static Func<object, object[], object> MakeFastInvoker(MethodInfo method)
{
Guard.NotNull(method, nameof(method));

var instanceParameterExpression = Expression.Parameter(typeof(object), "instance");
var argumentsParameterExpression = Expression.Parameter(typeof(object[]), "args");
var index = 0;

var argumentExtractionExpressions =
method
.GetParameters()
.Select(parameter =>
Expression.Convert(
Expression.ArrayAccess(
argumentsParameterExpression,
Expression.Constant(index++)
),
parameter.ParameterType
)
).ToList();

var callExpression = method.IsStatic
? Expression.Call(method, argumentExtractionExpressions)
: Expression.Call(
Expression.Convert(
instanceParameterExpression,
method.DeclaringType
),
method,
argumentExtractionExpressions
);

var endLabel = Expression.Label(typeof(object));

var finalExpression = method.ReturnType == typeof(void)
? (Expression)Expression.Block(
callExpression,
Expression.Return(endLabel, Expression.Constant(null)),
Expression.Label(endLabel, Expression.Constant(null))
)
: Expression.Convert(callExpression, typeof(object));

var lambdaExpression = Expression.Lambda<Func<object, object[], object>>(
finalExpression,
instanceParameterExpression,
argumentsParameterExpression
);

var lamdba = lambdaExpression.Compile();
return lamdba;
}

/// <summary>
/// Invokes a method using the specified object and parameter instances.
/// </summary>
/// <param name="obj">The objectinstance</param>
/// <param name="methodName">Method name</param>
/// <param name="parameterTypes">Argument types of the matching method overload (in exact order)</param>
/// <param name="parameters">Parameter instances to pass to invocation</param>
/// <returns>The method invocation result.</returns>
public static object Invoke(object obj, string methodName, Type[] parameterTypes, object[] parameters)
{
Guard.NotNull(obj, nameof(obj));

FastInvoker invoker;

if (parameterTypes == null || parameterTypes.Length == 0)
{
invoker = GetInvoker(obj.GetType(), methodName);
}
else
{
invoker = GetInvoker(obj.GetType(), methodName, parameterTypes);
}

//var hasAnyNullParam = parameters.Any(x => x == null);
//if (hasAnyNullParam)
//{
// throw new ArgumentException("When invoking a method with parameter instances, no instance must be null.", nameof(parameters));
//}

return invoker.Invoke(obj, parameters ?? Array.Empty<object>());
}

/// <summary>
/// Creates and caches a fast method invoker.
/// </summary>
/// <param name="methodInfo">Method info instance to create an invoker for.</param>
/// <returns>The fast method invoker.</returns>
public static FastInvoker GetInvoker(MethodInfo methodInfo)
{
Guard.NotNull(methodInfo, nameof(methodInfo));

return GetInvoker(
methodInfo.DeclaringType,
methodInfo.Name,
methodInfo.GetParameters().Select(x => x.ParameterType).ToArray());
}

/// <summary>
/// Creates and caches a fast method invoker.
/// </summary>
/// <param name="methodName">Name of method to create an invoker for.</param>
/// <param name="argTypes">Argument types of method to create an invoker for.</param>
/// <returns>The fast method invoker.</returns>
public static FastInvoker GetInvoker<T>(string methodName, params Type[] argTypes)
{
return GetInvoker(typeof(T), methodName, argTypes);
}

/// <summary>
/// Creates and caches a fast method invoker.
/// </summary>
/// <param name="type">The type to extract fast method invoker for.</param>
/// <param name="methodName">Name of method to create an invoker for.</param>
/// <param name="argTypes">Argument types of method to create an invoker for.</param>
/// <returns>The fast method invoker.</returns>
public static FastInvoker GetInvoker(Type type, string methodName, params Type[] argTypes)
{
Guard.NotNull(type, nameof(type));
Guard.NotEmpty(methodName, nameof(methodName));

var cacheKey = MethodKey.Create(type, methodName, argTypes);

if (!_invokersCache.TryGetValue(cacheKey, out var invoker))
{
var method = FindMatchingMethod(type, methodName, argTypes);

if (method == null)
{
throw new MethodAccessException("Could not find a matching method '{0}' in type {1}.".FormatInvariant(methodName, type));
}

invoker = new FastInvoker(method);
_invokersCache.TryAdd(cacheKey, invoker);
}

return invoker;
}

private static MethodInfo FindMatchingMethod(Type type, string methodName, Type[] argTypes)
{
var method = argTypes == null || argTypes.Length == 0
? type.GetMethod(methodName)
: type.GetMethod(
methodName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
null,
argTypes ?? new Type[0],
null);

return method;
}

#endregion

class MethodKey : Tuple<Type, string, int>
{
public MethodKey(Type type, string methodName, int parametersHash)
: base(type, methodName, parametersHash)
{
}
public Type Type { get { return base.Item1; } }
public string MethodName { get { return base.Item2; } }
public int ParameterHash { get { return base.Item3; } }

public static MethodKey Create(Type type, string methodName, IEnumerable<Type> parameterTypes)
{
var hashCombiner = HashCodeCombiner.Start().Add(parameterTypes);
return new MethodKey(type, methodName, hashCombiner.CombinedHash);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ protected static IDictionary<string, FastProperty> GetVisibleProperties(
{
return result;
}

// The simple and common case, this is normal POCO object - no need to allocate.
var allPropertiesDefinedOnType = true;
var allProperties = GetProperties(type, createPropertyHelper, allPropertiesCache);
Expand Down
2 changes: 0 additions & 2 deletions src/Libraries/SmartStore.Core/Data/IQueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace SmartStore
{
public static class IQueryableExtensions
{

/// <summary>
/// Instructs the repository to eager load entities that may be in the type's association path.
/// </summary>
Expand Down Expand Up @@ -40,6 +39,5 @@ public static IQueryable<T> Expand<T, TProperty>(this IQueryable<T> query, Expre

return query.Include(path);
}

}
}
39 changes: 14 additions & 25 deletions src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,21 @@ public partial class Product : BaseEntity, IAuditable, ISoftDeletable, ILocalize
{
#region static

private static readonly HashSet<string> _visibilityAffectingProductProps = new HashSet<string>();

static Product()
{
AddPropsToSet(_visibilityAffectingProductProps,
x => x.AvailableEndDateTimeUtc,
x => x.AvailableStartDateTimeUtc,
x => x.Deleted,
x => x.LowStockActivityId,
x => x.LimitedToStores,
x => x.ManageInventoryMethodId,
x => x.MinStockQuantity,
x => x.Published,
x => x.SubjectToAcl,
x => x.VisibleIndividually);
}

static void AddPropsToSet(HashSet<string> props, params Expression<Func<Product, object>>[] lambdas)
private static readonly HashSet<string> _visibilityAffectingProductProps = new HashSet<string>
{
foreach (var lambda in lambdas)
{
props.Add(lambda.ExtractPropertyInfo().Name);
}
}

public static HashSet<string> GetVisibilityAffectingPropertyNames()
nameof(Product.AvailableEndDateTimeUtc),
nameof(Product.AvailableStartDateTimeUtc),
nameof(Product.Deleted),
nameof(Product.LowStockActivityId),
nameof(Product.LimitedToStores),
nameof(Product.ManageInventoryMethodId),
nameof(Product.MinStockQuantity),
nameof(Product.Published),
nameof(Product.SubjectToAcl),
nameof(Product.VisibleIndividually)
};

public static IReadOnlyCollection<string> GetVisibilityAffectingPropertyNames()
{
return _visibilityAffectingProductProps;
}
Expand Down
Loading