This commit is contained in:
2021-10-21 20:46:04 +01:00
parent 60c1d0e8f8
commit 9e1c17e82a
8150 changed files with 715974 additions and 235 deletions
+190
View File
@@ -0,0 +1,190 @@
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
.vs/
[Dd]ebug/
[Rr]elease/
x64/
[Bb]in/
[Oo]bj/
# Build scripts folder
[Aa]pp[Bb]uild/
[Oo]ut/
# Visual Studio Code files
.vscode/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#######################
## nopCommerce specific
###########
glob:*.user
*.patch
*.hg
src/Presentation/Nop.Web/App_Data/browscap.crawlersonly.xml
src/Presentation/Nop.Web/App_Data/installedPlugins.json
src/Presentation/Nop.Web/App_Data/plugins.json
src/Presentation/Nop.Web/App_Data/dataSettings.json
src/Presentation/Nop.Web/App_Data/TempUploads/*
!src/Presentation/Nop.Web/App_Data/TempUploads/Index.htm
src/Presentation/Nop.Web/App_Data/DataProtectionKeys/*
!src/Presentation/Nop.Web/App_Data/DataProtectionKeys/Index.htm
src/Presentation/Nop.Web/Plugins/*
!src/Presentation/Nop.Web/Plugins/bin
src/Presentation/Nop.Web/Plugins/bin/*
!src/Presentation/Nop.Web/Plugins/bin/placeholder.txt
src/Presentation/Nop.Web/wwwroot/bundles/*
!src/Presentation/Nop.Web/wwwroot/bundles/Index.htm
src/Presentation/Nop.Web/wwwroot/db_backups/*.bak
!src/Presentation/Nop.Web/wwwroot/db_backups/Index.htm
src/Presentation/Nop.Web/wwwroot/images/thumbs/*
!src/Presentation/Nop.Web/wwwroot/images/thumbs/placeholder.txt
src/Presentation/Nop.Web/wwwroot/images/uploaded/*
!src/Presentation/Nop.Web/wwwroot/images/uploaded/placeholder.txt
src/Presentation/Nop.Web/wwwroot/files/exportimport/*
!src/Presentation/Nop.Web/wwwroot/files/exportimport/Index.htm
src/packages/*
+232
View File
@@ -0,0 +1,232 @@
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# Code files
[*.{cs,csx}]
indent_size = 4
insert_final_newline = false
charset = utf-8-bom
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.{json,travis.yml}]
indent_size = 2
# JS and CSS
[*.{js,css}]
indent_style = space
indent_size = 2
# min files don't reformatting
[*.min.*]
trim_trailing_whitespace = false
insert_final_newline = false
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
# this. preferences
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = always:suggestion
dotnet_style_readonly_field = false:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.camel_case_style.capitalization = camel_case
dotnet_naming_style.upper_case_style.capitalization = all_upper
dotnet_naming_style.upper_case_style.word_separator = _
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_style.private_field_style.required_prefix = _
dotnet_naming_style.private_field_style.capitalization = camel_case
# Use all upper for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = upper_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
# Use PascalCase for public fields
dotnet_naming_rule.pascal_case_for_public_fields.severity = warning
dotnet_naming_rule.pascal_case_for_public_fields.symbols = public_fields
dotnet_naming_rule.pascal_case_for_public_fields.style = pascal_case_style
dotnet_naming_symbols.public_fields.applicable_kinds = field
dotnet_naming_symbols.public_fields.applicable_accessibilities = public
# Interfaces must be PascalCase and have an I prefix
dotnet_naming_rule.interface_rule.severity = warning
dotnet_naming_rule.interface_rule.symbols = interface_group
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_naming_symbols.interface_group.applicable_kinds = interface
# Private fields must be camelCase and have an _ prefix
dotnet_naming_rule.private_field_with_.severity = warning
dotnet_naming_rule.private_field_with_.symbols = private_fields
dotnet_naming_rule.private_field_with_.style = private_field_style
dotnet_naming_symbols.private_fields.applicable_accessibilities = private,protected
dotnet_naming_symbols.private_fields.applicable_kinds = field
# Async methods should have "Async" suffix
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async
dotnet_naming_symbols.any_async_methods.applicable_kinds = method
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = *
dotnet_naming_symbols.any_async_methods.required_modifiers = async
dotnet_naming_style.end_in_async.required_prefix =
dotnet_naming_style.end_in_async.required_suffix = Async
dotnet_naming_style.end_in_async.capitalization = pascal_case
dotnet_naming_style.end_in_async.word_separator =
# Classes, structs, methods, enums, events, properties, namespaces, delegates must be PascalCase
dotnet_naming_rule.general_naming.severity = warning
dotnet_naming_rule.general_naming.symbols = general
dotnet_naming_rule.general_naming.style = pascal_case_style
dotnet_naming_symbols.general.applicable_kinds = class,struct,enum,property,method,event,delegate,namespace
dotnet_naming_symbols.general.applicable_accessibilities = *
# Use PascalCase for type parameters
dotnet_naming_rule.pascal_case_for_type_parameters.severity = suggestion
dotnet_naming_rule.pascal_case_for_type_parameters.symbols = type_parameters
dotnet_naming_rule.pascal_case_for_type_parameters.style = pascal_case_style
dotnet_naming_symbols.type_parameters.applicable_kinds = type_parameter
# Everything else is camelCase
dotnet_naming_rule.everything_else_naming.severity = warning
dotnet_naming_rule.everything_else_naming.symbols = everything_else
dotnet_naming_rule.everything_else_naming.style = camel_case_style
dotnet_naming_symbols.everything_else.applicable_kinds = *
dotnet_naming_symbols.everything_else.applicable_accessibilities = *
###############################
# C# Code Style Rules #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods = false:suggestion
csharp_style_expression_bodied_constructors = false:suggestion
csharp_style_expression_bodied_operators = false:suggestion
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion
# Pattern-matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = false:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = no_change
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_after_comma = true
csharp_space_after_dot = false
# Wrapping preferences
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
+13
View File
@@ -0,0 +1,13 @@
# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
# Explicitly declare text files we want to always be normalized and converted to native line endings on checkout.
*.sh text eol=lf
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
*.csproj text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png -text
*.jpg -text
+79 -233
View File
@@ -1,81 +1,42 @@
# ---> VisualStudio #################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files # User-specific files
*.rsuser
*.suo *.suo
*.user *.user
*.userosscache
*.sln.docstates *.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results # Build results
.vs/
[Dd]ebug/ [Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/ [Rr]elease/
[Rr]eleases/
x64/ x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory # Build scripts folder
.vs/ [Aa]pp[Bb]uild/
# Uncomment if you have tasks that create the project's static files in wwwroot [Oo]ut/
#wwwroot/
# Visual Studio 2017 auto generated files # Visual Studio Code files
Generated\ Files/ .vscode/
# MSTest test Results # MSTest test Results
[Tt]est[Rr]esult*/ [Tt]est[Rr]esult*/
[Bb]uild[Ll]og.* [Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c *_i.c
*_p.c *_p.c
*_h.h
*.ilk *.ilk
*.meta *.meta
*.obj *.obj
*.iobj
*.pch *.pch
*.pdb *.pdb
*.ipdb
*.pgc *.pgc
*.pgd *.pgd
*.rsp *.rsp
@@ -85,40 +46,26 @@ StyleCopReport.xml
*.tlh *.tlh
*.tmp *.tmp
*.tmp_proj *.tmp_proj
*_wpftmp.csproj
*.log *.log
*.vspscc *.vspscc
*.vssscc *.vssscc
.builds .builds
*.pidb *.pidb
*.svclog *.log
*.scc *.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files # Visual C++ cache files
ipch/ ipch/
*.aps *.aps
*.ncb *.ncb
*.opendb
*.opensdf *.opensdf
*.sdf *.sdf
*.cachefile *.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler # Visual Studio profiler
*.psess *.psess
*.vsp *.vsp
*.vspx *.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit # Guidance Automation Toolkit
*.gpState *.gpState
@@ -126,7 +73,6 @@ $tf/
# ReSharper is a .NET coding add-in # ReSharper is a .NET coding add-in
_ReSharper*/ _ReSharper*/
*.[Rr]e[Ss]harper *.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in # TeamCity is a build add-in
_TeamCity* _TeamCity*
@@ -134,28 +80,9 @@ _TeamCity*
# DotCover is a Code Coverage Tool # DotCover is a Code Coverage Tool
*.dotCover *.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch # NCrunch
_NCrunch_* *.ncrunch*
.*crunch*.local.xml .*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder # Installshield output folder
[Ee]xpress/ [Ee]xpress/
@@ -174,182 +101,101 @@ DocProject/Help/html
publish/ publish/
# Publish Web Output # Publish Web Output
*.[Pp]ublish.xml *.Publish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml *.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to #Launch settings
# checkin your Azure Web App publish settings, but sensitive information contained **/Properties/launchSettings.json
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages # NuGet Packages Directory
*.nupkg ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
# NuGet Symbol Packages #packages/
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output # Windows Azure Build Output
csx/ csx
*.build.csdef *.build.csdef
# Microsoft Azure Emulator # Windows Store app package directory
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others # Others
sql/
*.Cache
ClientBin/ ClientBin/
[Ss]tyle[Cc]op.*
~$* ~$*
*~ *~
*.dbmdl *.dbmdl
*.dbproj.schemaview *.[Pp]ublish.xml
*.jfm
*.pfx *.pfx
*.publishsettings *.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects # RIA/Silverlight projects
Generated_Code/ Generated_Code/
# Backup & report files from converting an old project file # Backup & report files from converting an old project file to a newer
# to a newer Visual Studio version. Backup files are not needed, # Visual Studio version. Backup files are not needed, because we have git ;-)
# because we have git ;-)
_UpgradeReport_Files/ _UpgradeReport_Files/
Backup*/ Backup*/
UpgradeLog*.XML UpgradeLog*.XML
UpgradeLog*.htm UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files # SQL Server files
*.mdf App_Data/*.mdf
*.ldf App_Data/*.ldf
*.ndf
# Business Intelligence projects #############
*.rdl.data ## Windows detritus
*.bim.layout #############
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes # Windows image file caches
FakesAssemblies/ Thumbs.db
ehthumbs.db
# GhostDoc plugin setting file # Folder config file
*.GhostDoc.xml Desktop.ini
# Node.js Tools for Visual Studio # Recycle Bin used on file shares
.ntvs_analysis.dat $RECYCLE.BIN/
node_modules/
# Visual Studio 6 build log # Mac crap
*.plg .DS_Store
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
#######################
## nopCommerce specific
###########
glob:*.user
*.patch
*.hg
src/Presentation/Nop.Web/.config/*
src/Presentation/Nop.Web/App_Data/browscap.xml
src/Presentation/Nop.Web/App_Data/installedPlugins.json
src/Presentation/Nop.Web/App_Data/plugins.json
src/Presentation/Nop.Web/App_Data/dataSettings.json
src/Presentation/Nop.Web/App_Data/appsettings.json
src/Presentation/Nop.Web/App_Data/TempUploads/*
!src/Presentation/Nop.Web/App_Data/TempUploads/Index.htm
src/Presentation/Nop.Web/App_Data/DataProtectionKeys/*
!src/Presentation/Nop.Web/App_Data/DataProtectionKeys/Index.htm
src/Presentation/Nop.Web/node_modules/*
src/Presentation/Nop.Web/Plugins/*
!src/Presentation/Nop.Web/Plugins/bin
src/Presentation/Nop.Web/Plugins/bin/*
!src/Presentation/Nop.Web/Plugins/bin/placeholder.txt
src/Presentation/Nop.Web/wwwroot/.well-known/*
!src/Presentation/Nop.Web/wwwroot/.well-known/Index.htm
src/Presentation/Nop.Web/wwwroot/bundles/*
!src/Presentation/Nop.Web/wwwroot/bundles/Index.htm
src/Presentation/Nop.Web/wwwroot/db_backups/*.bak
!src/Presentation/Nop.Web/wwwroot/db_backups/Index.htm
src/Presentation/Nop.Web/wwwroot/images/thumbs/*
!src/Presentation/Nop.Web/wwwroot/images/thumbs/placeholder.txt
src/Presentation/Nop.Web/wwwroot/images/uploaded/*
!src/Presentation/Nop.Web/wwwroot/images/uploaded/placeholder.txt
src/Presentation/Nop.Web/wwwroot/files/exportimport/*
!src/Presentation/Nop.Web/wwwroot/files/exportimport/Index.htm
src/Presentation/Nop.Web/wwwroot/lib_npm/cldr-data/main/*
!src/Presentation/Nop.Web/wwwroot/lib_npm/cldr-data/main/en/*
!src/Presentation/Nop.Web/wwwroot/lib_npm/cldr-data/main/main.zip
src/packages/*
+13
View File
@@ -0,0 +1,13 @@
language: csharp
mono: none
dotnet: 5.0
dist: xenial
sudo: required
install:
- dotnet restore ./src/NopCommerce.sln
script:
- dotnet build ./src/NopCommerce.sln
- dotnet test ./src/Tests/Nop.Tests/Nop.Tests.csproj
notifications:
slack:
secure: iGN5bidszVkPqiyP+WVDGARYjjj4L7EprUZAqIJqz7mswAdgDlULuEfH+o3bN2qXZMBjKSXwLBx6te23Ehk+cs+5ESR7PigFIFNTW/+4eNxYoEjlDKoxsqNhBA7cJveKbdMl3E/Ka0DtmO23yjZla8AB+AZq3j7RxATjpwrjCFJ9RbSE7fVUvc6Q1GRjROb9CX6BAsICq7nvKSvr0LEJ2c7fXiVPFCE0aVMXAz0cFnOPECB7rQRQvC/mP8Wl+hd80Nhs8Plo81hV1zrdi93IBk4MFLVVhppOXVcvW7JlmiBe3qmiU0XL5riP7TMilGN2oSJHoHyZ9QSquox5BwoqBJNwGMgaJ1MZ4AlUu0DFQmZFZFZexmD83JZnkoe2FEqDJoYwru6SEC9Vq29FDWpMVTWaDO7OfXKXN1qy8POq6mCoa0/j7pTzDRYij+vnrM+JigNMstQhpvzCa+sLfzAgjbb9X2W1NQyAFUl0LC8Kyh+Klx9+Qz3nB1a+c586YYAfVwRxIXxKkRk/dPyi6k8x9msr9qg5AgBs7EkxYn8HcJEZjWdbUKW2uIsMR8SvUdJqlkj9Tf886troGs31gD74AVfFFl8ujcTr0sL2TgWbRLLGVgFvpjzx3g/xqdZivtsl/ybnszKwA/YthhxmZx+pURGG8fZt0hRfmVjSZbwYq2c=
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@nopCommerce.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+15
View File
@@ -0,0 +1,15 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change.
You are more than welcome to contribute to the success of nopCommerce by helping out in the realization of the project, by participating in the forums, or just by spreading the word! If you have a site, write about us or place a hyperlink! We are committed to nurturing the growth of the nopCommerce community!
Possible ways to contribute: [more info](http://docs.nopcommerce.com/display/en/Possible+ways+to+contribute)
Working with source code and contributions: [more info](http://docs.nopcommerce.com/display/en/Working+with+source+code+and+contributions)
Sharing your plugins, themes, and language packs: [more info](http://docs.nopcommerce.com/display/en/Sharing+your+plugins%2C+themes%2C+and+language+packs)
Contributing to the documentation: [more info](http://docs.nopcommerce.com/display/en/Contributing+to+the+documentation)
+84
View File
@@ -0,0 +1,84 @@
# create the build instance
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ./src ./
# restore solution
RUN dotnet restore NopCommerce.sln
WORKDIR /src/Presentation/Nop.Web
# build project
RUN dotnet build Nop.Web.csproj -c Release
# build plugins
WORKDIR /src/Plugins/Nop.Plugin.DiscountRules.CustomerRoles
RUN dotnet build Nop.Plugin.DiscountRules.CustomerRoles.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.ExchangeRate.EcbExchange
RUN dotnet build Nop.Plugin.ExchangeRate.EcbExchange.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.ExternalAuth.Facebook
RUN dotnet build Nop.Plugin.ExternalAuth.Facebook.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Misc.Sendinblue
RUN dotnet build Nop.Plugin.Misc.Sendinblue.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Payments.CheckMoneyOrder
RUN dotnet build Nop.Plugin.Payments.CheckMoneyOrder.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Payments.Manual
RUN dotnet build Nop.Plugin.Payments.Manual.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Payments.PayPalCommerce
RUN dotnet build Nop.Plugin.Payments.PayPalCommerce.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Payments.PayPalStandard
RUN dotnet build Nop.Plugin.Payments.PayPalStandard.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Pickup.PickupInStore
RUN dotnet build Nop.Plugin.Pickup.PickupInStore.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Shipping.FixedByWeightByTotal
RUN dotnet build Nop.Plugin.Shipping.FixedByWeightByTotal.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Shipping.ShipStation
RUN dotnet build Nop.Plugin.Shipping.ShipStation.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Shipping.UPS
RUN dotnet build Nop.Plugin.Shipping.UPS.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Tax.Avalara
RUN dotnet build Nop.Plugin.Tax.Avalara.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Tax.FixedOrByCountryStateZip
RUN dotnet build Nop.Plugin.Tax.FixedOrByCountryStateZip.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Widgets.AccessiBe
RUN dotnet build Nop.Plugin.Widgets.AccessiBe.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Widgets.FacebookPixel
RUN dotnet build Nop.Plugin.Widgets.FacebookPixel.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Widgets.GoogleAnalytics
RUN dotnet build Nop.Plugin.Widgets.GoogleAnalytics.csproj -c Release
WORKDIR /src/Plugins/Nop.Plugin.Widgets.NivoSlider
RUN dotnet build Nop.Plugin.Widgets.NivoSlider.csproj -c Release
# publish project
WORKDIR /src/Presentation/Nop.Web
RUN dotnet publish Nop.Web.csproj -c Release -o /app/published
# create the runtime instance
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS runtime
# add globalization support
RUN apk add --no-cache icu-libs
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# installs required packages
RUN apk add libgdiplus --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted
RUN apk add libc-dev --no-cache
# copy entrypoint script
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
WORKDIR /app
RUN mkdir bin
RUN mkdir logs
# create empty App_Data/datasettings.json to allow using datasettings environment variables
RUN mkdir App_Data
WORKDIR /app/App_Data
RUN echo "" > dataSettings.json
WORKDIR /app
COPY --from=build /app/published .
ENTRYPOINT "/entrypoint.sh"
+3
View File
@@ -0,0 +1,3 @@
nopCommerce version:
Steps to reproduce the problem:
+11
View File
@@ -0,0 +1,11 @@
nopCommerce Public License Version 3.0 ("NPL")
nopCommerce open source edition is licensed under nopCommerce Public License. It's basically a GPLv3 License plus the "powered by nopCommerce" text requirement on every single page. The nopCommerce Public License Version 3.0 ("NPL") consists of the GPL3 License with the Additional Terms below. The original GPLv3 License can be found at: http://opensource.org/licenses/GPL-3.0
Additional nopCommerce terms:
However, in addition to the other notice obligations, (1) all copies of the Program in Executable and Source Code form must, as a form of attribution of the original author, include on each user interface screen (i) the "powered by nopCommerce" text; and (2) all derivative works and copies of derivative works of the Covered Code in Executable and Source Code form must include on each user interface screen (i) the "powered by nopCommerce" text. In addition, the "powered by nopCommerce" text, as appropriate, must be visible to all users, must appear in each user interface screen, and must be in the same position. When users click on the "powered by nopCommerce" text it must direct them to https://www.nopCommerce.com. This obligation shall also apply to any copies or derivative works. Find more info at https://www.nopcommerce.com/p/1/nopcommerce-copyright-removal-key.aspx
License page: https://www.nopcommerce.com/licensev3.aspx
+81 -2
View File
@@ -1,3 +1,82 @@
# TheGoodwoodFlooringCompany nopCommerce: free and open-source eCommerce solution[![Build Status](https://travis-ci.com/nopSolutions/nopCommerce.svg?branch=develop)](https://travis-ci.com/nopSolutions/nopCommerce)
===========
ngebgviuer [nopCommerce](https://www.nopcommerce.com/?utm_source=github&utm_medium=content&utm_campaign=homepage) is the best open-source eCommerce shopping cart solution. nopCommerce is free, and it is the most popular ASP.NET eCommerce platform.
![nopCommerce demo](https://www.nopcommerce.com/images/github/responsive_devices_codeplex.png#v1)
The product is being developed and supported by the professional team since 2008.
nopCommerce has been downloaded more than 3,000,000 times.
The active developer community has more than 250,000 members.
nopCommerce runs on ASP.NET Core 5 with an MS SQL 2012 (or higher) backend database.
nopCommerce is cross-platform, and you can run it on Windows, Linux, or Mac.
nopCommerce supports Docker and MySQL out of the box, so you can easily run nopCommerce on a Linux machine.
nopCommerce supports PostgreSQL database.
nopCommerce fully supports web farms. You can read more about it [here](https://docs.nopcommerce.com/en/developer/tutorials/web-farms.html?utm_source=github&utm_medium=referral&utm_campaign=documentation&utm_content=text).
All methods in nopCommerce are async.
nopCommerce supports multi-factor authentication out of the box.
![Logo](https://www.nopcommerce.com/images/github/logos.png#v2)
nopCommerce architecture follows well-known software patterns and the best security practices. The source code is fully customizable. Pluggable and clear architecture makes it easy to develop custom functionality and follow any business requirements.
Using the latest Microsoft technologies, nopCommerce provides high performance, stability, and security. nopCommerce is also fully compatible with Azure and web farms.
Clear and detailed [documentation for developers](https://docs.nopcommerce.com/developer/index.html?utm_source=github&utm_medium=referral&utm_campaign=documentation&utm_content=text) will help you start with nopCommerce easily.
### The advantages of working with nopCommerce ###
nopCommerce offers powerful [out-of-the-box features](https://www.nopcommerce.com/features?utm_source=github&utm_medium=referral&utm_campaign=features&utm_content=text) for creating an online store of any size and type.
nopCommerce is integrated with all the popular third-party services. You can find thousands of integrations on nopCommerce [Marketplace](https://www.nopcommerce.com/marketplace?utm_source=github&utm_medium=referral&utm_campaign=marketplace&utm_content=text).
Friendly members of the [nopCommerce community](https://www.nopcommerce.com/boards?utm_source=github&utm_medium=referral&utm_campaign=forum&utm_content=text) will always help with advice and share their experiences. nopCommerce core development team provides [professional support](https://www.nopcommerce.com/nopcommerce-premium-support-services?utm_source=github&utm_medium=referral&utm_campaign=premium_support&utm_content=text) within 24 hours.
## Store demo ##
Evaluate the functionality and convenience of nopCommerce as a customer and store owner.
Front End | Admin area
----|------
[![ScreenShot](https://www.nopcommerce.com/images/github/public-demo.png#v1)](https://frontend.nopcommerce.com?utm_source=github&utm_medium=referral&utm_campaign=demo_store&utm_content=button) | [![ScreenShot](https://www.nopcommerce.com/images/github/admin-demo.png#v1)](https://admin-demo.nopcommerce.com/admin?utm_source=github&utm_medium=referral&utm_campaign=demo_store&utm_content=button)
### nopCommerce resources ###
nopCommerce official site: [https://www.nopcommerce.com](https://www.nopcommerce.com/?utm_source=github&utm_medium=referral&utm_campaign=homepage&utm_content=links)
* [Demo store](https://www.nopcommerce.com/demo?utm_source=github&utm_medium=referral&utm_campaign=demo_store&utm_content=links)
* [Download nopCommerce](https://www.nopcommerce.com/download-nopcommerce?utm_source=github&utm_medium=referral&utm_campaign=download_nop&utm_content=links)
* [Feature list](https://www.nopcommerce.com/features?utm_source=github&utm_medium=referral&utm_campaign=features&utm_content=links)
* [nopCommerce documentation](https://docs.nopcommerce.com?utm_source=github&utm_medium=referral&utm_campaign=documentation&utm_content=links)
* [Community forums](https://www.nopcommerce.com/boards?utm_source=github&utm_medium=referral&utm_campaign=forum&utm_content=links)
* [Premium support services](https://www.nopcommerce.com/nopcommerce-premium-support-services?utm_source=github&utm_medium=referral&utm_campaign=premium_support&utm_content=links)
* [Certified developer program](https://www.nopcommerce.com/certified-developer-program?utm_source=github&utm_medium=referral&utm_campaign=certified_developer&utm_content=links)
* [nopCommerce partners](https://www.nopcommerce.com/partners?utm_source=github&utm_medium=referral&utm_campaign=solution_partners&utm_content=links)
nopCommerce YouTube: [The Architecture behind the nopCommerce eCommerce Platform](https://www.youtube.com/watch?v=6gLbizzSA9o&list=PLnL_aDfmRHwtJmzeA7SxrpH3-XDY2ue0a)
### Earn with nopCommerce ###
60,000 stores worldwide are powered by nopCommerce, and 10,000 new stores open every year. nopCommerce [solution partners’ directory](https://www.nopcommerce.com/partners?utm_source=github&utm_medium=referral&utm_campaign=solution_partners&utm_content=text_become_partner) gets 80,000+ page views per year from store owners who are looking for a partner to build a store from scratch, migrate from another platform, or improve and customize an existing store.
Become a solution partner of nopCommerce and get new clients – [learn more](https://www.nopcommerce.com/become-partner?utm_source=github&utm_medium=referral&utm_campaign=become-partner&utm_content=learn_more).
Create a new graphical theme or develop a new plugin or integration and sell it on the nopCommerce [Marketplace](https://www.nopcommerce.com/marketplace?utm_source=github&utm_medium=referral&utm_campaign=marketplace&utm_content=text_sell_on_marketplace).
### Contribute ###
As a free and open-source project, we are very grateful to everyone who helps us to develop nopCommerce. Please find more details about the options and bonuses for contributors at [сontribute page](https://www.nopcommerce.com/contribute?utm_source=github&utm_medium=referral&utm_campaign=contribute&utm_content=text).
+19
View File
@@ -0,0 +1,19 @@
version: "3.4"
services:
nopcommerce_web:
build: .
container_name: nopcommerce
ports:
- "80:80"
depends_on:
- nopcommerce_database
nopcommerce_database:
image: "mcr.microsoft.com/mssql/server:2019-latest"
container_name: nopcommerce_mssql_server
environment:
SA_PASSWORD: "nopCommerce_db_password"
ACCEPT_EULA: "Y"
MSSQL_PID: "Express"
volumes:
nopcommerce_data:
+2
View File
@@ -0,0 +1,2 @@
ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2
exec dotnet Nop.Web.dll
+7
View File
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "5.0.103",
"rollForward": "latestFeature",
"allowPrerelease": false
}
}
+19
View File
@@ -0,0 +1,19 @@
version: "3.4"
services:
nopcommerce_web:
build: .
container_name: nopcommerce
ports:
- "80:80"
depends_on:
- nopcommerce_database
nopcommerce_database:
image: "mysql:latest"
container_name: nopcommerce_mysql_server
command: "--default-authentication-plugin=mysql_native_password"
restart: "always"
environment:
MYSQL_ROOT_PASSWORD: "nopCommerce_db_password"
volumes:
nopcommerce_data:
+18
View File
@@ -0,0 +1,18 @@
version: "3.4"
services:
nopcommerce_web:
build: .
container_name: nopcommerce
ports:
- "80:80"
depends_on:
- nopcommerce_database
nopcommerce_database:
image: "postgres:latest"
container_name: nopcommerce_postgres_server
restart: "always"
environment:
POSTGRES_PASSWORD: "nopCommerce_db_password"
volumes:
nopcommerce_data:
+2
View File
@@ -0,0 +1,2 @@
[config]
command = deploy.cmd
Binary file not shown.
+24
View File
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Copyright>Copyright © Nop Solutions, Ltd</Copyright>
<Company>Nop Solutions, Ltd</Company>
<Authors>Nop Solutions, Ltd</Authors>
<PackageLicenseUrl>http://www.nopcommerce.com/licensev3.aspx</PackageLicenseUrl>
<PackageProjectUrl>http://www.nopcommerce.com/</PackageProjectUrl>
<RepositoryUrl>https://github.com/nopSolutions/nopCommerce</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<OutputPath>$(MSBuildProjectDirectory)\..\Presentation\Nop.Web\bin\$(Configuration)</OutputPath>
</PropertyGroup>
<Target Name="NopClear">
<!-- When .NET Core builds a project, it copies all referenced libraries to the output folder.
For plugins it creates too many unnecessary files that just take up space.
At the moment you can't disable this behavior. That's why we have to manually delete all unnecessary libraries from plugin output directories. -->
<Exec Command='dotnet "ClearPluginAssemblies.dll" "OutputPath=$(OutputPath)|PluginPath=$(PluginPath)|SaveLocalesFolders=$(SaveLocalesFolders)"' />
</Target>
</Project>
@@ -0,0 +1,9 @@
{
"runtimeOptions": {
"tfm": "net5.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "5.0.1"
}
}
}
+6
View File
@@ -0,0 +1,6 @@
When .NET Core builds a project, it copies all referenced libraries to the output folder.
For plugins it creates too many unnecessary files that just take up space.
At the moment you can't disable this behavior. That's why we have to manually delete all unnecessary libraries from plugin output directories.
ClearPluginAssemblies.proj file contains preparation steps for delete unnecessary files.
ClearPluginAssemblies.dll file contains the code for deleting unnecessary files. This file is compiled from the project code from the src directory.
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClearPluginAssemblies", "ClearPluginAssemblies\ClearPluginAssemblies.csproj", "{98B26C68-16E7-4545-ACE7-1A6FBBFC2E92}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{98B26C68-16E7-4545-ACE7-1A6FBBFC2E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98B26C68-16E7-4545-ACE7-1A6FBBFC2E92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98B26C68-16E7-4545-ACE7-1A6FBBFC2E92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98B26C68-16E7-4545-ACE7-1A6FBBFC2E92}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E029116-51FD-4D73-AA78-4E26C730BFEB}
EndGlobalSection
EndGlobal
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<ApplicationIcon />
<StartupObject />
</PropertyGroup>
</Project>
@@ -0,0 +1,103 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ClearPluginAssemblies
{
public class Program
{
protected const string FILES_TO_DELETE = "dotnet-bundle.exe;Nop.Web.pdb;Nop.Web.exe;Nop.Web.exe.config";
protected static void Clear(string paths, IList<string> fileNames, bool saveLocalesFolders)
{
foreach (var pluginPath in paths.Split(';'))
{
try
{
var pluginDirectoryInfo = new DirectoryInfo(pluginPath);
var allDirectoryInfo = new List<DirectoryInfo> { pluginDirectoryInfo };
if (!saveLocalesFolders)
allDirectoryInfo.AddRange(pluginDirectoryInfo.GetDirectories());
foreach (var directoryInfo in allDirectoryInfo)
{
foreach (var fileName in fileNames)
{
//delete dll file if it exists in current path
var dllfilePath = Path.Combine(directoryInfo.FullName, fileName + ".dll");
if (File.Exists(dllfilePath))
File.Delete(dllfilePath);
//delete pdb file if it exists in current path
var pdbfilePath = Path.Combine(directoryInfo.FullName, fileName + ".pdb");
if (File.Exists(pdbfilePath))
File.Delete(pdbfilePath);
}
foreach (var fileName in FILES_TO_DELETE.Split(';'))
{
//delete file if it exists in current path
var pdbfilePath = Path.Combine(directoryInfo.FullName, fileName);
if (File.Exists(pdbfilePath))
File.Delete(pdbfilePath);
}
if (!directoryInfo.GetFiles().Any() && !directoryInfo.GetDirectories().Any() && !saveLocalesFolders)
directoryInfo.Delete(true);
}
}
catch
{
//do nothing
}
}
}
private static void Main(string[] args)
{
var outputPath = string.Empty;
var pluginPaths = string.Empty;
var saveLocalesFolders = true;
var settings = args.FirstOrDefault(a => a.Contains("|")) ?? string.Empty;
if(string.IsNullOrEmpty(settings))
return;
foreach (var arg in settings.Split('|'))
{
var data = arg.Split("=").Select(p => p.Trim()).ToList();
var name = data[0];
var value = data.Count > 1 ? data[1] : string.Empty;
switch (name)
{
case "OutputPath":
outputPath = value;
break;
case "PluginPath":
pluginPaths = value;
break;
case "SaveLocalesFolders":
bool.TryParse(value, out saveLocalesFolders);
break;
}
}
if(!Directory.Exists(outputPath))
return;
var di = new DirectoryInfo(outputPath);
var fileNames = di.GetFiles("*.dll", SearchOption.AllDirectories)
.Where(fi => !fi.FullName.Contains(@"\Plugins\"))
.Select(fi => fi.Name.Replace(fi.Extension, "")).ToList();
if (string.IsNullOrEmpty(pluginPaths) || !fileNames.Any())
{
return;
}
Clear(pluginPaths, fileNames, saveLocalesFolders);
}
}
}
+5
View File
@@ -0,0 +1,5 @@
1. Open the solution in Visual Studio
2. Re-build the entire solution
3. Publish the "Nop.Web" project from Visual Studio
P.S. When publishing ensure that configuration is set to "Release"
+11
View File
@@ -0,0 +1,11 @@
nopCommerce Public License Version 3.0 ("NPL")
nopCommerce open source edition is licensed under nopCommerce Public License. It's basically a GPLv3 License plus the "powered by nopCommerce" text requirement on every single page. The nopCommerce Public License Version 3.0 ("NPL") consists of the GPL3 License with the Additional Terms below. The original GPLv3 License can be found at: http://opensource.org/licenses/GPL-3.0
Additional nopCommerce terms:
However, in addition to the other notice obligations, (1) all copies of the Program in Executable and Source Code form must, as a form of attribution of the original author, include on each user interface screen (i) the "powered by nopCommerce" text; and (2) all derivative works and copies of derivative works of the Covered Code in Executable and Source Code form must include on each user interface screen (i) the "powered by nopCommerce" text. In addition, the "powered by nopCommerce" text, as appropriate, must be visible to all users, must appear in each user interface screen, and must be in the same position. When users click on the "powered by nopCommerce" text it must direct them to http://www.nopCommerce.com. This obligation shall also apply to any copies or derivative works. Find more info at http://www.nopcommerce.com/p/1/nopcommerce-copyright-removal-key.aspx
License page: http://www.nopcommerce.com/licensev3.aspx
+13
View File
@@ -0,0 +1,13 @@
namespace Nop.Core
{
/// <summary>
/// Represents the base class for entities
/// </summary>
public abstract partial class BaseEntity
{
/// <summary>
/// Gets or sets the entity identifier
/// </summary>
public int Id { get; set; }
}
}
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure;
namespace Nop.Core.Caching
{
/// <summary>
/// Represents key for caching objects
/// </summary>
public partial class CacheKey
{
#region Ctor
/// <summary>
/// Initialize a new instance with key and prefixes
/// </summary>
/// <param name="key">Key</param>
/// <param name="prefixes">Prefixes for remove by prefix functionality</param>
public CacheKey(string key, params string[] prefixes)
{
Key = key;
Prefixes.AddRange(prefixes.Where(prefix => !string.IsNullOrEmpty(prefix)));
}
#endregion
#region Methods
/// <summary>
/// Create a new instance from the current one and fill it with passed parameters
/// </summary>
/// <param name="createCacheKeyParameters">Function to create parameters</param>
/// <param name="keyObjects">Objects to create parameters</param>
/// <returns>Cache key</returns>
public virtual CacheKey Create(Func<object, object> createCacheKeyParameters, params object[] keyObjects)
{
var cacheKey = new CacheKey(Key, Prefixes.ToArray());
if (!keyObjects.Any())
return cacheKey;
cacheKey.Key = string.Format(cacheKey.Key, keyObjects.Select(createCacheKeyParameters).ToArray());
for (var i = 0; i < cacheKey.Prefixes.Count; i++)
cacheKey.Prefixes[i] = string.Format(cacheKey.Prefixes[i], keyObjects.Select(createCacheKeyParameters).ToArray());
return cacheKey;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets a cache key
/// </summary>
public string Key { get; protected set; }
/// <summary>
/// Gets or sets prefixes for remove by prefix functionality
/// </summary>
public List<string> Prefixes { get; protected set; } = new List<string>();
/// <summary>
/// Gets or sets a cache time in minutes
/// </summary>
public int CacheTime { get; set; } = Singleton<AppSettings>.Instance.Get<CacheConfig>().DefaultCacheTime;
#endregion
}
}
@@ -0,0 +1,133 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Nop.Core.Configuration;
namespace Nop.Core.Caching
{
/// <summary>
/// Represents the default cache key service implementation
/// </summary>
public abstract partial class CacheKeyService
{
#region Constants
/// <summary>
/// Gets an algorithm used to create the hash value of identifiers need to cache
/// </summary>
private string HashAlgorithm => "SHA1";
#endregion
#region Fields
protected readonly AppSettings _appSettings;
#endregion
#region Ctor
protected CacheKeyService(AppSettings appSettings)
{
_appSettings = appSettings;
}
#endregion
#region Utilities
/// <summary>
/// Prepare the cache key prefix
/// </summary>
/// <param name="prefix">Cache key prefix</param>
/// <param name="prefixParameters">Parameters to create cache key prefix</param>
protected virtual string PrepareKeyPrefix(string prefix, params object[] prefixParameters)
{
return prefixParameters?.Any() ?? false
? string.Format(prefix, prefixParameters.Select(CreateCacheKeyParameters).ToArray())
: prefix;
}
/// <summary>
/// Create the hash value of the passed identifiers
/// </summary>
/// <param name="ids">Collection of identifiers</param>
/// <returns>String hash value</returns>
protected virtual string CreateIdsHash(IEnumerable<int> ids)
{
var identifiers = ids.ToList();
if (!identifiers.Any())
return string.Empty;
var identifiersString = string.Join(", ", identifiers.OrderBy(id => id));
return HashHelper.CreateHash(Encoding.UTF8.GetBytes(identifiersString), HashAlgorithm);
}
/// <summary>
/// Converts an object to cache parameter
/// </summary>
/// <param name="parameter">Object to convert</param>
/// <returns>Cache parameter</returns>
protected virtual object CreateCacheKeyParameters(object parameter)
{
return parameter switch
{
null => "null",
IEnumerable<int> ids => CreateIdsHash(ids),
IEnumerable<BaseEntity> entities => CreateIdsHash(entities.Select(entity => entity.Id)),
BaseEntity entity => entity.Id,
decimal param => param.ToString(CultureInfo.InvariantCulture),
_ => parameter
};
}
#endregion
#region Methods
/// <summary>
/// Create a copy of cache key and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
public virtual CacheKey PrepareKey(CacheKey cacheKey, params object[] cacheKeyParameters)
{
return cacheKey.Create(CreateCacheKeyParameters, cacheKeyParameters);
}
/// <summary>
/// Create a copy of cache key using the default cache time and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
public virtual CacheKey PrepareKeyForDefaultCache(CacheKey cacheKey, params object[] cacheKeyParameters)
{
var key = cacheKey.Create(CreateCacheKeyParameters, cacheKeyParameters);
key.CacheTime = _appSettings.Get<CacheConfig>().DefaultCacheTime;
return key;
}
/// <summary>
/// Create a copy of cache key using the short cache time and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
public virtual CacheKey PrepareKeyForShortTermCache(CacheKey cacheKey, params object[] cacheKeyParameters)
{
var key = cacheKey.Create(CreateCacheKeyParameters, cacheKeyParameters);
key.CacheTime = _appSettings.Get<CacheConfig>().ShortTermCacheTime;
return key;
}
#endregion
}
}
@@ -0,0 +1,492 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using Nito.AsyncEx;
using Nop.Core.ComponentModel;
using Nop.Core.Configuration;
namespace Nop.Core.Caching
{
/// <summary>
/// Represents a distributed cache
/// </summary>
public partial class DistributedCacheManager: CacheKeyService, ILocker, IStaticCacheManager
{
#region Fields
private readonly IDistributedCache _distributedCache;
private readonly PerRequestCache _perRequestCache;
private static readonly List<string> _keys;
private static readonly AsyncLock _locker;
#endregion
#region Ctor
static DistributedCacheManager()
{
_locker = new AsyncLock();
_keys = new List<string>();
}
public DistributedCacheManager(AppSettings appSettings, IDistributedCache distributedCache, IHttpContextAccessor httpContextAccessor) :base(appSettings)
{
_distributedCache = distributedCache;
_perRequestCache = new PerRequestCache(httpContextAccessor);
}
#endregion
#region Utilities
/// <summary>
/// Prepare cache entry options for the passed key
/// </summary>
/// <param name="key">Cache key</param>
/// <returns>Cache entry options</returns>
private DistributedCacheEntryOptions PrepareEntryOptions(CacheKey key)
{
//set expiration time for the passed cache key
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(key.CacheTime)
};
return options;
}
/// <summary>
/// Try to get the cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the flag which indicate is the key exists in the cache, cached item or default value
/// </returns>
private async Task<(bool isSet, T item)> TryGetItemAsync<T>(CacheKey key)
{
var json = await _distributedCache.GetStringAsync(key.Key);
if (string.IsNullOrEmpty(json))
return (false, default);
var item = JsonConvert.DeserializeObject<T>(json);
_perRequestCache.Set(key.Key, item);
return (true, item);
}
/// <summary>
/// Try to get the cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <returns>Flag which indicate is the key exists in the cache, cached item or default value</returns>
private (bool isSet, T item) TryGetItem<T>(CacheKey key)
{
var json = _distributedCache.GetString(key.Key);
if (string.IsNullOrEmpty(json))
return (false, default);
var item = JsonConvert.DeserializeObject<T>(json);
_perRequestCache.Set(key.Key, item);
return (true, item);
}
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
private void Set(CacheKey key, object data)
{
if ((key?.CacheTime ?? 0) <= 0 || data == null)
return;
_distributedCache.SetString(key.Key, JsonConvert.SerializeObject(data), PrepareEntryOptions(key));
_perRequestCache.Set(key.Key, data);
using var _ = _locker.Lock();
_keys.Add(key.Key);
}
#endregion
#region Methods
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
public async Task<T> GetAsync<T>(CacheKey key, Func<Task<T>> acquire)
{
//little performance workaround here:
//we use "PerRequestCache" to cache a loaded object in memory for the current HTTP request.
//this way we won't connect to Redis server many times per HTTP request (e.g. each time to load a locale or setting)
if (_perRequestCache.IsSet(key.Key))
return _perRequestCache.Get(key.Key, () => default(T));
if (key.CacheTime <= 0)
return await acquire();
var (isSet, item) = await TryGetItemAsync<T>(key);
if (isSet)
return item;
var result = await acquire();
if (result != null)
await SetAsync(key, result);
return result;
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
public async Task<T> GetAsync<T>(CacheKey key, Func<T> acquire)
{
//little performance workaround here:
//we use "PerRequestCache" to cache a loaded object in memory for the current HTTP request.
//this way we won't connect to Redis server many times per HTTP request (e.g. each time to load a locale or setting)
if (_perRequestCache.IsSet(key.Key))
return _perRequestCache.Get(key.Key, () => default(T));
if (key.CacheTime <= 0)
return acquire();
var (isSet, item) = await TryGetItemAsync<T>(key);
if (isSet)
return item;
var result = acquire();
if (result != null)
await SetAsync(key, result);
return result;
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>The cached value associated with the specified key</returns>
public T Get<T>(CacheKey key, Func<T> acquire)
{
//little performance workaround here:
//we use "PerRequestCache" to cache a loaded object in memory for the current HTTP request.
//this way we won't connect to Redis server many times per HTTP request (e.g. each time to load a locale or setting)
if (_perRequestCache.IsSet(key.Key))
return _perRequestCache.Get(key.Key, () => default(T));
if (key.CacheTime <= 0)
return acquire();
var (isSet, item) = TryGetItem<T>(key);
if (isSet)
return item;
var result = acquire();
if (result != null)
Set(key, result);
return result;
}
/// <summary>
/// Remove the value with the specified key from the cache
/// </summary>
/// <param name="cacheKey">Cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>A task that represents the asynchronous operation</returns>
public async Task RemoveAsync(CacheKey cacheKey, params object[] cacheKeyParameters)
{
cacheKey = PrepareKey(cacheKey, cacheKeyParameters);
await _distributedCache.RemoveAsync(cacheKey.Key);
_perRequestCache.Remove(cacheKey.Key);
using var _ = await _locker.LockAsync();
_keys.Remove(cacheKey.Key);
}
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
/// <returns>A task that represents the asynchronous operation</returns>
public async Task SetAsync(CacheKey key, object data)
{
if ((key?.CacheTime ?? 0) <= 0 || data == null)
return;
await _distributedCache.SetStringAsync(key.Key, JsonConvert.SerializeObject(data), PrepareEntryOptions(key));
_perRequestCache.Set(key.Key, data);
using var _ = await _locker.LockAsync();
_keys.Add(key.Key);
}
/// <summary>
/// Remove items by cache key prefix
/// </summary>
/// <param name="prefix">Cache key prefix</param>
/// <param name="prefixParameters">Parameters to create cache key prefix</param>
/// <returns>A task that represents the asynchronous operation</returns>
public async Task RemoveByPrefixAsync(string prefix, params object[] prefixParameters)
{
prefix = PrepareKeyPrefix(prefix, prefixParameters);
_perRequestCache.RemoveByPrefix(prefix);
using var _ = await _locker.LockAsync();
foreach (var key in _keys.Where(key => key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase)).ToList())
{
await _distributedCache.RemoveAsync(key);
_keys.Remove(key);
}
}
/// <summary>
/// Clear all cache data
/// </summary>
/// <returns>A task that represents the asynchronous operation</returns>
public async Task ClearAsync()
{
//we can't use _perRequestCache.Clear(),
//because HttpContext stores some server data that we should not delete
foreach (var redisKey in _keys)
_perRequestCache.Remove(redisKey);
using var _ = await _locker.LockAsync();
foreach (var key in _keys)
await _distributedCache.RemoveAsync(key);
_keys.Clear();
}
/// <summary>
/// Perform some action with exclusive lock
/// </summary>
/// <param name="resource">The key we are locking on</param>
/// <param name="expirationTime">The time after which the lock will automatically be expired</param>
/// <param name="action">Action to be performed with locking</param>
/// <returns>True if lock was acquired and action was performed; otherwise false</returns>
public bool PerformActionWithLock(string resource, TimeSpan expirationTime, Action action)
{
//ensure that lock is acquired
if (!string.IsNullOrEmpty(_distributedCache.GetString(resource)))
return false;
try
{
_distributedCache.SetString(resource, resource, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = expirationTime
});
//perform action
action();
return true;
}
finally
{
//release lock even if action fails
_distributedCache.Remove(resource);
}
}
#endregion
#region Nested class
/// <summary>
/// Represents a manager for caching during an HTTP request (short term caching)
/// </summary>
protected class PerRequestCache
{
#region Fields
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ReaderWriterLockSlim _lockSlim;
#endregion
#region Ctor
public PerRequestCache(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
_lockSlim = new ReaderWriterLockSlim();
}
#endregion
#region Utilities
/// <summary>
/// Get a key/value collection that can be used to share data within the scope of this request
/// </summary>
protected virtual IDictionary<object, object> GetItems()
{
return _httpContextAccessor.HttpContext?.Items;
}
#endregion
#region Methods
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>The cached value associated with the specified key</returns>
public virtual T Get<T>(string key, Func<T> acquire)
{
IDictionary<object, object> items;
using (new ReaderWriteLockDisposable(_lockSlim, ReaderWriteLockType.Read))
{
items = GetItems();
if (items == null)
return acquire();
//item already is in cache, so return it
if (items[key] != null)
return (T)items[key];
}
//or create it using passed function
var result = acquire();
//and set in cache (if cache time is defined)
using (new ReaderWriteLockDisposable(_lockSlim))
items[key] = result;
return result;
}
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
public virtual void Set(string key, object data)
{
if (data == null)
return;
using (new ReaderWriteLockDisposable(_lockSlim))
{
var items = GetItems();
if (items == null)
return;
items[key] = data;
}
}
/// <summary>
/// Get a value indicating whether the value associated with the specified key is cached
/// </summary>
/// <param name="key">Key of cached item</param>
/// <returns>True if item already is in cache; otherwise false</returns>
public virtual bool IsSet(string key)
{
using (new ReaderWriteLockDisposable(_lockSlim, ReaderWriteLockType.Read))
{
var items = GetItems();
return items?[key] != null;
}
}
/// <summary>
/// Remove the value with the specified key from the cache
/// </summary>
/// <param name="key">Key of cached item</param>
public virtual void Remove(string key)
{
using (new ReaderWriteLockDisposable(_lockSlim))
{
var items = GetItems();
items?.Remove(key);
}
}
/// <summary>
/// Remove items by key prefix
/// </summary>
/// <param name="prefix">String key prefix</param>
public virtual void RemoveByPrefix(string prefix)
{
using (new ReaderWriteLockDisposable(_lockSlim, ReaderWriteLockType.UpgradeableRead))
{
var items = GetItems();
if (items == null)
return;
//get cache keys that matches pattern
var regex = new Regex(prefix,
RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
var matchesKeys = items.Keys.Select(p => p.ToString())
.Where(key => regex.IsMatch(key ?? string.Empty)).ToList();
if (!matchesKeys.Any())
return;
using (new ReaderWriteLockDisposable(_lockSlim))
//remove matching values
foreach (var key in matchesKeys)
items.Remove(key);
}
}
#endregion
}
#endregion
}
}
+16
View File
@@ -0,0 +1,16 @@
using System;
namespace Nop.Core.Caching
{
public interface ILocker
{
/// <summary>
/// Perform some action with exclusive lock
/// </summary>
/// <param name="resource">The key we are locking on</param>
/// <param name="expirationTime">The time after which the lock will automatically be expired</param>
/// <param name="action">Action to be performed with locking</param>
/// <returns>True if lock was acquired and action was performed; otherwise false</returns>
bool PerformActionWithLock(string resource, TimeSpan expirationTime, Action action);
}
}
@@ -0,0 +1,102 @@
using System;
using System.Threading.Tasks;
namespace Nop.Core.Caching
{
/// <summary>
/// Represents a manager for caching between HTTP requests (long term caching)
/// </summary>
public interface IStaticCacheManager : IDisposable
{
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
Task<T> GetAsync<T>(CacheKey key, Func<Task<T>> acquire);
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
Task<T> GetAsync<T>(CacheKey key, Func<T> acquire);
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>The cached value associated with the specified key</returns>
T Get<T>(CacheKey key, Func<T> acquire);
/// <summary>
/// Remove the value with the specified key from the cache
/// </summary>
/// <param name="cacheKey">Cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task RemoveAsync(CacheKey cacheKey, params object[] cacheKeyParameters);
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task SetAsync(CacheKey key, object data);
/// <summary>
/// Remove items by cache key prefix
/// </summary>
/// <param name="prefix">Cache key prefix</param>
/// <param name="prefixParameters">Parameters to create cache key prefix</param>
/// <returns>A task that represents the asynchronous operation</returns>
Task RemoveByPrefixAsync(string prefix, params object[] prefixParameters);
/// <summary>
/// Clear all cache data
/// </summary>
/// <returns>A task that represents the asynchronous operation</returns>
Task ClearAsync();
#region Cache key
/// <summary>
/// Create a copy of cache key and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
CacheKey PrepareKey(CacheKey cacheKey, params object[] cacheKeyParameters);
/// <summary>
/// Create a copy of cache key using the default cache time and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
CacheKey PrepareKeyForDefaultCache(CacheKey cacheKey, params object[] cacheKeyParameters);
/// <summary>
/// Create a copy of cache key using the short cache time and fills it by passed parameters
/// </summary>
/// <param name="cacheKey">Initial cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>Cache key</returns>
CacheKey PrepareKeyForShortTermCache(CacheKey cacheKey, params object[] cacheKeyParameters);
#endregion
}
}
@@ -0,0 +1,285 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using Nop.Core.Configuration;
namespace Nop.Core.Caching
{
/// <summary>
/// Represents a memory cache manager
/// </summary>
public partial class MemoryCacheManager : CacheKeyService, ILocker, IStaticCacheManager
{
#region Fields
// Flag: Has Dispose already been called?
private bool _disposed;
private readonly IMemoryCache _memoryCache;
private static readonly ConcurrentDictionary<string, CancellationTokenSource> _prefixes = new ConcurrentDictionary<string, CancellationTokenSource>();
private static CancellationTokenSource _clearToken = new CancellationTokenSource();
#endregion
#region Ctor
public MemoryCacheManager(AppSettings appSettings, IMemoryCache memoryCache) : base(appSettings)
{
_memoryCache = memoryCache;
}
#endregion
#region Utilities
/// <summary>
/// Prepare cache entry options for the passed key
/// </summary>
/// <param name="key">Cache key</param>
/// <returns>Cache entry options</returns>
private MemoryCacheEntryOptions PrepareEntryOptions(CacheKey key)
{
//set expiration time for the passed cache key
var options = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(key.CacheTime)
};
//add tokens to clear cache entries
options.AddExpirationToken(new CancellationChangeToken(_clearToken.Token));
foreach (var keyPrefix in key.Prefixes.ToList())
{
var tokenSource = _prefixes.GetOrAdd(keyPrefix, new CancellationTokenSource());
options.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));
}
return options;
}
/// <summary>
/// Remove the value with the specified key from the cache
/// </summary>
/// <param name="cacheKey">Cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
private void Remove(CacheKey cacheKey, params object[] cacheKeyParameters)
{
cacheKey = PrepareKey(cacheKey, cacheKeyParameters);
_memoryCache.Remove(cacheKey.Key);
}
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
private void Set(CacheKey key, object data)
{
if ((key?.CacheTime ?? 0) <= 0 || data == null)
return;
_memoryCache.Set(key.Key, data, PrepareEntryOptions(key));
}
#endregion
#region Methods
/// <summary>
/// Remove the value with the specified key from the cache
/// </summary>
/// <param name="cacheKey">Cache key</param>
/// <param name="cacheKeyParameters">Parameters to create cache key</param>
/// <returns>A task that represents the asynchronous operation</returns>
public Task RemoveAsync(CacheKey cacheKey, params object[] cacheKeyParameters)
{
Remove(cacheKey, cacheKeyParameters);
return Task.CompletedTask;
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
public async Task<T> GetAsync<T>(CacheKey key, Func<Task<T>> acquire)
{
if ((key?.CacheTime ?? 0) <= 0)
return await acquire();
if (_memoryCache.TryGetValue(key.Key, out T result))
return result;
result = await acquire();
if(result != null)
await SetAsync(key, result);
return result;
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the cached value associated with the specified key
/// </returns>
public async Task<T> GetAsync<T>(CacheKey key, Func<T> acquire)
{
if ((key?.CacheTime ?? 0) <= 0)
return acquire();
var result = _memoryCache.GetOrCreate(key.Key, entry =>
{
entry.SetOptions(PrepareEntryOptions(key));
return acquire();
});
//do not cache null value
if (result == null)
await RemoveAsync(key);
return result;
}
/// <summary>
/// Get a cached item. If it's not in the cache yet, then load and cache it
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Cache key</param>
/// <param name="acquire">Function to load item if it's not in the cache yet</param>
/// <returns>The cached value associated with the specified key</returns>
public T Get<T>(CacheKey key, Func<T> acquire)
{
if ((key?.CacheTime ?? 0) <= 0)
return acquire();
if (_memoryCache.TryGetValue(key.Key, out T result))
return result;
result = acquire();
if (result != null)
Set(key, result);
return result;
}
/// <summary>
/// Add the specified key and object to the cache
/// </summary>
/// <param name="key">Key of cached item</param>
/// <param name="data">Value for caching</param>
/// <returns>A task that represents the asynchronous operation</returns>
public Task SetAsync(CacheKey key, object data)
{
Set(key, data);
return Task.CompletedTask;
}
/// <summary>
/// Perform some action with exclusive in-memory lock
/// </summary>
/// <param name="key">The key we are locking on</param>
/// <param name="expirationTime">The time after which the lock will automatically be expired</param>
/// <param name="action">Action to be performed with locking</param>
/// <returns>True if lock was acquired and action was performed; otherwise false</returns>
public bool PerformActionWithLock(string key, TimeSpan expirationTime, Action action)
{
//ensure that lock is acquired
if (_memoryCache.TryGetValue(key, out _))
return false;
try
{
_memoryCache.Set(key, key, expirationTime);
//perform action
action();
return true;
}
finally
{
//release lock even if action fails
_memoryCache.Remove(key);
}
}
/// <summary>
/// Remove items by cache key prefix
/// </summary>
/// <param name="prefix">Cache key prefix</param>
/// <param name="prefixParameters">Parameters to create cache key prefix</param>
/// <returns>A task that represents the asynchronous operation</returns>
public Task RemoveByPrefixAsync(string prefix, params object[] prefixParameters)
{
prefix = PrepareKeyPrefix(prefix, prefixParameters);
_prefixes.TryRemove(prefix, out var tokenSource);
tokenSource?.Cancel();
tokenSource?.Dispose();
return Task.CompletedTask;
}
/// <summary>
/// Clear all cache data
/// </summary>
/// <returns>A task that represents the asynchronous operation</returns>
public Task ClearAsync()
{
_clearToken.Cancel();
_clearToken.Dispose();
_clearToken = new CancellationTokenSource();
foreach (var prefix in _prefixes.Keys.ToList())
{
_prefixes.TryRemove(prefix, out var tokenSource);
tokenSource?.Dispose();
}
return Task.CompletedTask;
}
/// <summary>
/// Dispose cache manager
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
_memoryCache.Dispose();
_disposed = true;
}
#endregion
}
}
@@ -0,0 +1,54 @@
namespace Nop.Core.Caching
{
/// <summary>
/// Represents default values related to caching entities
/// </summary>
public static partial class NopEntityCacheDefaults<TEntity> where TEntity : BaseEntity
{
/// <summary>
/// Gets an entity type name used in cache keys
/// </summary>
public static string EntityTypeName => typeof(TEntity).Name.ToLowerInvariant();
/// <summary>
/// Gets a key for caching entity by identifier
/// </summary>
/// <remarks>
/// {0} : entity id
/// </remarks>
public static CacheKey ByIdCacheKey => new CacheKey($"Nop.{EntityTypeName}.byid.{{0}}", ByIdPrefix, Prefix);
/// <summary>
/// Gets a key for caching entities by identifiers
/// </summary>
/// <remarks>
/// {0} : entity ids
/// </remarks>
public static CacheKey ByIdsCacheKey => new CacheKey($"Nop.{EntityTypeName}.byids.{{0}}", ByIdsPrefix, Prefix);
/// <summary>
/// Gets a key for caching all entities
/// </summary>
public static CacheKey AllCacheKey => new CacheKey($"Nop.{EntityTypeName}.all.", AllPrefix, Prefix);
/// <summary>
/// Gets a key pattern to clear cache
/// </summary>
public static string Prefix => $"Nop.{EntityTypeName}.";
/// <summary>
/// Gets a key pattern to clear cache
/// </summary>
public static string ByIdPrefix => $"Nop.{EntityTypeName}.byid.";
/// <summary>
/// Gets a key pattern to clear cache
/// </summary>
public static string ByIdsPrefix => $"Nop.{EntityTypeName}.byids.";
/// <summary>
/// Gets a key pattern to clear cache
/// </summary>
public static string AllPrefix => $"Nop.{EntityTypeName}.all.";
}
}
+333
View File
@@ -0,0 +1,333 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using Nop.Core.Infrastructure;
namespace Nop.Core
{
/// <summary>
/// Represents a common helper
/// </summary>
public partial class CommonHelper
{
#region Fields
//we use EmailValidator from FluentValidation. So let's keep them sync - https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation/Validators/EmailValidator.cs
private const string EMAIL_EXPRESSION = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$";
private static readonly Regex _emailRegex;
#endregion
#region Ctor
static CommonHelper()
{
_emailRegex = new Regex(EMAIL_EXPRESSION, RegexOptions.IgnoreCase);
}
#endregion
#region Methods
/// <summary>
/// Ensures the subscriber email or throw.
/// </summary>
/// <param name="email">The email.</param>
/// <returns></returns>
public static string EnsureSubscriberEmailOrThrow(string email)
{
var output = EnsureNotNull(email);
output = output.Trim();
output = EnsureMaximumLength(output, 255);
if (!IsValidEmail(output))
{
throw new NopException("Email is not valid.");
}
return output;
}
/// <summary>
/// Verifies that a string is in valid e-mail format
/// </summary>
/// <param name="email">Email to verify</param>
/// <returns>true if the string is a valid e-mail address and false if it's not</returns>
public static bool IsValidEmail(string email)
{
if (string.IsNullOrEmpty(email))
return false;
email = email.Trim();
return _emailRegex.IsMatch(email);
}
/// <summary>
/// Verifies that string is an valid IP-Address
/// </summary>
/// <param name="ipAddress">IPAddress to verify</param>
/// <returns>true if the string is a valid IpAddress and false if it's not</returns>
public static bool IsValidIpAddress(string ipAddress)
{
return IPAddress.TryParse(ipAddress, out var _);
}
/// <summary>
/// Generate random digit code
/// </summary>
/// <param name="length">Length</param>
/// <returns>Result string</returns>
public static string GenerateRandomDigitCode(int length)
{
using var random = new SecureRandomNumberGenerator();
var str = string.Empty;
for (var i = 0; i < length; i++)
str = string.Concat(str, random.Next(10).ToString());
return str;
}
/// <summary>
/// Returns an random integer number within a specified rage
/// </summary>
/// <param name="min">Minimum number</param>
/// <param name="max">Maximum number</param>
/// <returns>Result</returns>
public static int GenerateRandomInteger(int min = 0, int max = int.MaxValue)
{
using var random = new SecureRandomNumberGenerator();
return random.Next(min, max);
}
/// <summary>
/// Ensure that a string doesn't exceed maximum allowed length
/// </summary>
/// <param name="str">Input string</param>
/// <param name="maxLength">Maximum length</param>
/// <param name="postfix">A string to add to the end if the original string was shorten</param>
/// <returns>Input string if its length is OK; otherwise, truncated input string</returns>
public static string EnsureMaximumLength(string str, int maxLength, string postfix = null)
{
if (string.IsNullOrEmpty(str))
return str;
if (str.Length <= maxLength)
return str;
var pLen = postfix?.Length ?? 0;
var result = str[0..(maxLength - pLen)];
if (!string.IsNullOrEmpty(postfix))
{
result += postfix;
}
return result;
}
/// <summary>
/// Ensures that a string only contains numeric values
/// </summary>
/// <param name="str">Input string</param>
/// <returns>Input string with only numeric values, empty string if input is null/empty</returns>
public static string EnsureNumericOnly(string str)
{
return string.IsNullOrEmpty(str) ? string.Empty : new string(str.Where(char.IsDigit).ToArray());
}
/// <summary>
/// Ensure that a string is not null
/// </summary>
/// <param name="str">Input string</param>
/// <returns>Result</returns>
public static string EnsureNotNull(string str)
{
return str ?? string.Empty;
}
/// <summary>
/// Indicates whether the specified strings are null or empty strings
/// </summary>
/// <param name="stringsToValidate">Array of strings to validate</param>
/// <returns>Boolean</returns>
public static bool AreNullOrEmpty(params string[] stringsToValidate)
{
return stringsToValidate.Any(string.IsNullOrEmpty);
}
/// <summary>
/// Compare two arrays
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="a1">Array 1</param>
/// <param name="a2">Array 2</param>
/// <returns>Result</returns>
public static bool ArraysEqual<T>(T[] a1, T[] a2)
{
//also see Enumerable.SequenceEqual(a1, a2);
if (ReferenceEquals(a1, a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
var comparer = EqualityComparer<T>.Default;
return !a1.Where((t, i) => !comparer.Equals(t, a2[i])).Any();
}
/// <summary>
/// Sets a property on an object to a value.
/// </summary>
/// <param name="instance">The object whose property to set.</param>
/// <param name="propertyName">The name of the property to set.</param>
/// <param name="value">The value to set the property to.</param>
public static void SetProperty(object instance, string propertyName, object value)
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));
if (propertyName == null)
throw new ArgumentNullException(nameof(propertyName));
var instanceType = instance.GetType();
var pi = instanceType.GetProperty(propertyName);
if (pi == null)
throw new NopException("No property '{0}' found on the instance of type '{1}'.", propertyName, instanceType);
if (!pi.CanWrite)
throw new NopException("The property '{0}' on the instance of type '{1}' does not have a setter.", propertyName, instanceType);
if (value != null && !value.GetType().IsAssignableFrom(pi.PropertyType))
value = To(value, pi.PropertyType);
pi.SetValue(instance, value, Array.Empty<object>());
}
/// <summary>
/// Converts a value to a destination type.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="destinationType">The type to convert the value to.</param>
/// <returns>The converted value.</returns>
public static object To(object value, Type destinationType)
{
return To(value, destinationType, CultureInfo.InvariantCulture);
}
/// <summary>
/// Converts a value to a destination type.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="destinationType">The type to convert the value to.</param>
/// <param name="culture">Culture</param>
/// <returns>The converted value.</returns>
public static object To(object value, Type destinationType, CultureInfo culture)
{
if (value == null)
return null;
var sourceType = value.GetType();
var destinationConverter = TypeDescriptor.GetConverter(destinationType);
if (destinationConverter.CanConvertFrom(value.GetType()))
return destinationConverter.ConvertFrom(null, culture, value);
var sourceConverter = TypeDescriptor.GetConverter(sourceType);
if (sourceConverter.CanConvertTo(destinationType))
return sourceConverter.ConvertTo(null, culture, value, destinationType);
if (destinationType.IsEnum && value is int)
return Enum.ToObject(destinationType, (int)value);
if (!destinationType.IsInstanceOfType(value))
return Convert.ChangeType(value, destinationType, culture);
return value;
}
/// <summary>
/// Converts a value to a destination type.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <typeparam name="T">The type to convert the value to.</typeparam>
/// <returns>The converted value.</returns>
public static T To<T>(object value)
{
//return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
return (T)To(value, typeof(T));
}
/// <summary>
/// Convert enum for front-end
/// </summary>
/// <param name="str">Input string</param>
/// <returns>Converted string</returns>
public static string ConvertEnum(string str)
{
if (string.IsNullOrEmpty(str))
return string.Empty;
var result = string.Empty;
foreach (var c in str)
if (c.ToString() != c.ToString().ToLower())
result += " " + c.ToString();
else
result += c.ToString();
//ensure no spaces (e.g. when the first letter is upper case)
result = result.TrimStart();
return result;
}
/// <summary>
/// Get difference in years
/// </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public static int GetDifferenceInYears(DateTime startDate, DateTime endDate)
{
//source: http://stackoverflow.com/questions/9/how-do-i-calculate-someones-age-in-c
//this assumes you are looking for the western idea of age and not using East Asian reckoning.
var age = endDate.Year - startDate.Year;
if (startDate > endDate.AddYears(-age))
age--;
return age;
}
/// <summary>
/// Get DateTime to the specified year, month, and day using the conventions of the current thread culture
/// </summary>
/// <param name="year">The year</param>
/// <param name="month">The month</param>
/// <param name="day">The day</param>
/// <returns>An instance of the Nullable<System.DateTime></returns>
public static DateTime? ParseDate(int? year, int? month, int? day)
{
if (!year.HasValue || !month.HasValue || !day.HasValue)
return null;
DateTime? date = null;
try
{
date = new DateTime(year.Value, month.Value, day.Value, CultureInfo.CurrentCulture.Calendar);
}
catch { }
return date;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the default file provider
/// </summary>
public static INopFileProvider DefaultFileProvider { get; set; }
#endregion
}
}
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Nop.Core.ComponentModel
{
/// <summary>
/// Generic Dictionary type converted
/// </summary>
/// <typeparam name="K">Key type (simple)</typeparam>
/// <typeparam name="V">Value type (simple)</typeparam>
public class GenericDictionaryTypeConverter<K, V> : TypeConverter
{
/// <summary>
/// Type converter
/// </summary>
protected readonly TypeConverter typeConverterKey;
/// <summary>
/// Type converter
/// </summary>
protected readonly TypeConverter typeConverterValue;
public GenericDictionaryTypeConverter()
{
typeConverterKey = TypeDescriptor.GetConverter(typeof(K));
if (typeConverterKey == null)
throw new InvalidOperationException("No type converter exists for type " + typeof(K).FullName);
typeConverterValue = TypeDescriptor.GetConverter(typeof(V));
if (typeConverterValue == null)
throw new InvalidOperationException("No type converter exists for type " + typeof(V).FullName);
}
/// <summary>
/// Gets a value indicating whether this converter can
/// convert an object in the given source type to the native type of the converter
/// using the context.
/// </summary>
/// <param name="context">Context</param>
/// <param name="sourceType">Source type</param>
/// <returns>Result</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// Converts the given object to the converter's native type.
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <returns>Result</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is string))
return base.ConvertFrom(context, culture, value);
var input = (string)value;
var items = string.IsNullOrEmpty(input) ? Array.Empty<string>() : input.Split(';').Select(x => x.Trim()).ToArray();
var result = new Dictionary<K, V>();
Array.ForEach(items, s =>
{
var keyValueStr = string.IsNullOrEmpty(s) ? Array.Empty<string>() : s.Split(',').Select(x => x.Trim()).ToArray();
if (keyValueStr.Length != 2)
return;
object dictionaryKey = (K)typeConverterKey.ConvertFromInvariantString(keyValueStr[0]);
object dictionaryValue = (V)typeConverterValue.ConvertFromInvariantString(keyValueStr[1]);
if (dictionaryKey == null || dictionaryValue == null)
return;
if (!result.ContainsKey((K)dictionaryKey))
result.Add((K)dictionaryKey, (V)dictionaryValue);
});
return result;
}
/// <summary>
/// Converts the given value object to the specified destination type using the specified context and arguments
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <param name="destinationType">Destination type</param>
/// <returns>Result</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(string))
return base.ConvertTo(context, culture, value, destinationType);
var result = string.Empty;
if (value == null)
return result;
//we don't use string.Join() because it doesn't support invariant culture
var counter = 0;
var dictionary = (IDictionary<K, V>)value;
foreach (var keyValue in dictionary)
{
result += $"{Convert.ToString(keyValue.Key, CultureInfo.InvariantCulture)}, {Convert.ToString(keyValue.Value, CultureInfo.InvariantCulture)}";
//don't add ; after the last element
if (counter != dictionary.Count - 1)
result += ";";
counter++;
}
return result;
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Nop.Core.ComponentModel
{
/// <summary>
/// Generic List type converted
/// </summary>
/// <typeparam name="T">Type</typeparam>
public class GenericListTypeConverter<T> : TypeConverter
{
/// <summary>
/// Type converter
/// </summary>
protected readonly TypeConverter typeConverter;
public GenericListTypeConverter()
{
typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter == null)
throw new InvalidOperationException("No type converter exists for type " + typeof(T).FullName);
}
/// <summary>
/// Get string array from a comma-separate string
/// </summary>
/// <param name="input">Input</param>
/// <returns>Array</returns>
protected virtual string[] GetStringArray(string input)
{
return string.IsNullOrEmpty(input) ? Array.Empty<string>() : input.Split(',').Select(x => x.Trim()).ToArray();
}
/// <summary>
/// Gets a value indicating whether this converter can
/// convert an object in the given source type to the native type of the converter
/// using the context.
/// </summary>
/// <param name="context">Context</param>
/// <param name="sourceType">Source type</param>
/// <returns>Result</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType != typeof(string))
return base.CanConvertFrom(context, sourceType);
var items = GetStringArray(sourceType.ToString());
return items.Any();
}
/// <summary>
/// Converts the given object to the converter's native type.
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <returns>Result</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is string) && value != null)
return base.ConvertFrom(context, culture, value);
var items = GetStringArray((string)value);
var result = new List<T>();
Array.ForEach(items, s =>
{
var item = typeConverter.ConvertFromInvariantString(s);
if (item != null)
{
result.Add((T)item);
}
});
return result;
}
/// <summary>
/// Converts the given value object to the specified destination type using the specified context and arguments
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <param name="destinationType">Destination type</param>
/// <returns>Result</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(string))
return base.ConvertTo(context, culture, value, destinationType);
var result = string.Empty;
if (value == null)
return result;
//we don't use string.Join() because it doesn't support invariant culture
for (var i = 0; i < ((IList<T>)value).Count; i++)
{
var str1 = Convert.ToString(((IList<T>)value)[i], CultureInfo.InvariantCulture);
result += str1;
//don't add comma after the last element
if (i != ((IList<T>)value).Count - 1)
result += ",";
}
return result;
}
}
}
@@ -0,0 +1,73 @@
using System;
using System.Threading;
namespace Nop.Core.ComponentModel
{
/// <summary>
/// Provides a convenience methodology for implementing locked access to resources.
/// </summary>
/// <remarks>
/// Intended as an infrastructure class.
/// </remarks>
public class ReaderWriteLockDisposable : IDisposable
{
private bool _disposed = false;
private readonly ReaderWriterLockSlim _rwLock;
private readonly ReaderWriteLockType _readerWriteLockType;
/// <summary>
/// Initializes a new instance of the <see cref="ReaderWriteLockDisposable"/> class.
/// </summary>
/// <param name="rwLock">The readers–writer lock</param>
/// <param name="readerWriteLockType">Lock type</param>
public ReaderWriteLockDisposable(ReaderWriterLockSlim rwLock, ReaderWriteLockType readerWriteLockType = ReaderWriteLockType.Write)
{
_rwLock = rwLock;
_readerWriteLockType = readerWriteLockType;
switch (_readerWriteLockType)
{
case ReaderWriteLockType.Read:
_rwLock.EnterReadLock();
break;
case ReaderWriteLockType.Write:
_rwLock.EnterWriteLock();
break;
case ReaderWriteLockType.UpgradeableRead:
_rwLock.EnterUpgradeableReadLock();
break;
}
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
switch (_readerWriteLockType)
{
case ReaderWriteLockType.Read:
_rwLock.ExitReadLock();
break;
case ReaderWriteLockType.Write:
_rwLock.ExitWriteLock();
break;
case ReaderWriteLockType.UpgradeableRead:
_rwLock.ExitUpgradeableReadLock();
break;
}
}
_disposed = true;
}
}
}
@@ -0,0 +1,12 @@
namespace Nop.Core.ComponentModel
{
/// <summary>
/// Reader/Write locker type
/// </summary>
public enum ReaderWriteLockType
{
Read,
Write,
UpgradeableRead
}
}
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents the app settings
/// </summary>
public partial class AppSettings
{
#region Fields
private readonly Dictionary<Type, IConfig> _configurations = new();
#endregion
#region Ctor
public AppSettings(IList<IConfig> configurations = null)
{
_configurations = configurations
?.OrderBy(config => config.GetOrder())
?.ToDictionary(config => config.GetType(), config => config)
?? new Dictionary<Type, IConfig>();
}
#endregion
#region Properties
/// <summary>
/// Gets or sets raw configuration parameters
/// </summary>
[JsonExtensionData]
public Dictionary<string, JToken> Configuration { get; set; }
#endregion
#region Methods
/// <summary>
/// Get configuration parameters by type
/// </summary>
/// <typeparam name="TConfig">Configuration type</typeparam>
/// <returns>Configuration parameters</returns>
public TConfig Get<TConfig>() where TConfig : class, IConfig
{
if (_configurations[typeof(TConfig)] is not TConfig config)
throw new NopException($"No configuration with type '{typeof(TConfig)}' found");
return config;
}
/// <summary>
/// Update app settings
/// </summary>
/// <param name="configurations">Configurations to update</param>
public void Update(IList<IConfig> configurations)
{
foreach (var config in configurations)
{
_configurations[config.GetType()] = config;
}
}
#endregion
}
}
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Nop.Core.Infrastructure;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents the app settings helper
/// </summary>
public partial class AppSettingsHelper
{
#region Methods
/// <summary>
/// Create app settings with the passed configurations and save it to the file
/// </summary>
/// <param name="configurations">Configurations to save</param>
/// <param name="fileProvider">File provider</param>
/// <param name="overwrite">Whether to overwrite appsettings file</param>
/// <returns>App settings</returns>
public static AppSettings SaveAppSettings(IList<IConfig> configurations, INopFileProvider fileProvider, bool overwrite = true)
{
if (configurations is null)
throw new ArgumentNullException(nameof(configurations));
//create app settings
var appSettings = Singleton<AppSettings>.Instance ?? new AppSettings();
appSettings.Update(configurations);
Singleton<AppSettings>.Instance = appSettings;
//create file if not exists
var filePath = fileProvider.MapPath(NopConfigurationDefaults.AppSettingsFilePath);
var fileExists = fileProvider.FileExists(filePath);
fileProvider.CreateFile(filePath);
//get raw configuration parameters
var configuration = JsonConvert.DeserializeObject<AppSettings>(fileProvider.ReadAllText(filePath, Encoding.UTF8))
?.Configuration
?? new();
foreach (var config in configurations)
{
configuration[config.Name] = JToken.FromObject(config);
}
//sort configurations for display by order (e.g. data configuration with 0 will be the first)
appSettings.Configuration = configuration
.SelectMany(outConfig => configurations.Where(inConfig => inConfig.Name == outConfig.Key).DefaultIfEmpty(),
(outConfig, inConfig) => new { OutConfig = outConfig, InConfig = inConfig })
.OrderBy(config => config.InConfig?.GetOrder() ?? int.MaxValue)
.Select(config => config.OutConfig)
.ToDictionary(config => config.Key, config => config.Value);
//save app settings to the file
if (!fileExists || overwrite)
{
var text = JsonConvert.SerializeObject(appSettings, Formatting.Indented);
fileProvider.WriteAllText(filePath, text, Encoding.UTF8);
}
return appSettings;
}
#endregion
}
}
@@ -0,0 +1,45 @@
using System.Linq;
using System.Collections.Generic;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents the event that is raised when App Settings are saving
/// </summary>
public class AppSettingsSavingEvent
{
#region Ctor
public AppSettingsSavingEvent(IList<IConfig> configurations)
{
Configurations = configurations;
}
#endregion
#region Properties
/// <summary>
/// Gets configurations to save
/// </summary>
public IList<IConfig> Configurations { get; private set; }
#endregion
#region Methods
/// <summary>
/// Add configuration to save
/// </summary>
/// <param name="config">Configuration to save</param>
public void AddConfig<TConfig>(TConfig config) where TConfig : class, IConfig
{
if (Configurations.OfType<TConfig>().FirstOrDefault() is TConfig currentConfig)
Configurations[Configurations.IndexOf(currentConfig)] = config;
else
Configurations.Add(config);
}
#endregion
}
}
@@ -0,0 +1,57 @@
using Newtonsoft.Json;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents Azure Blob storage configuration parameters
/// </summary>
public partial class AzureBlobConfig : IConfig
{
/// <summary>
/// Gets or sets connection string for Azure Blob storage
/// </summary>
public string ConnectionString { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets container name for Azure Blob storage
/// </summary>
public string ContainerName { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets end point for Azure Blob storage
/// </summary>
public string EndPoint { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets whether or the Container Name is appended to the AzureBlobStorageEndPoint when constructing the url
/// </summary>
public bool AppendContainerName { get; private set; } = true;
/// <summary>
/// Gets or sets whether to store Data Protection Keys in Azure Blob Storage
/// </summary>
public bool StoreDataProtectionKeys { get; private set; } = false;
/// <summary>
/// Gets or sets the Azure container name for storing Data Prtection Keys (this container should be separate from the container used for media and should be Private)
/// </summary>
public string DataProtectionKeysContainerName { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets the Azure key vault ID used to encrypt the Data Protection Keys. (this is optional)
/// </summary>
public string DataProtectionKeysVaultId { get; private set; } = string.Empty;
/// <summary>
/// Gets a value indicating whether we should use Azure Blob storage
/// </summary>
[JsonIgnore]
public bool Enabled => !string.IsNullOrEmpty(ConnectionString);
/// <summary>
/// Whether to use an Azure Key Vault to encrypt the Data Protection Keys
/// </summary>
[JsonIgnore]
public bool DataProtectionKeysEncryptWithVault => !string.IsNullOrEmpty(DataProtectionKeysVaultId);
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents cache configuration parameters
/// </summary>
public partial class CacheConfig : IConfig
{
/// <summary>
/// Gets or sets the default cache time in minutes
/// </summary>
public int DefaultCacheTime { get; private set; } = 60;
/// <summary>
/// Gets or sets the short term cache time in minutes
/// </summary>
public int ShortTermCacheTime { get; private set; } = 3;
/// <summary>
/// Gets or sets the bundled files cache time in minutes
/// </summary>
public int BundledFilesCacheTime { get; private set; } = 120;
}
}
@@ -0,0 +1,59 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents common configuration parameters
/// </summary>
public partial class CommonConfig : IConfig
{
/// <summary>
/// Gets or sets a value indicating whether to display the full error in production environment. It's ignored (always enabled) in development environment
/// </summary>
public bool DisplayFullErrorStack { get; private set; } = false;
/// <summary>
/// Gets or sets path to database with user agent strings
/// </summary>
public string UserAgentStringsPath { get; private set; } = "~/App_Data/browscap.xml";
/// <summary>
/// Gets or sets path to database with crawler only user agent strings
/// </summary>
public string CrawlerOnlyUserAgentStringsPath { get; private set; } = "~/App_Data/browscap.crawlersonly.xml";
/// <summary>
/// Gets or sets a value indicating whether to store TempData in the session state. By default the cookie-based TempData provider is used to store TempData in cookies.
/// </summary>
public bool UseSessionStateTempDataProvider { get; private set; } = false;
/// <summary>
/// Gets or sets a value that indicates whether to use MiniProfiler services
/// </summary>
public bool MiniProfilerEnabled { get; private set; } = false;
/// <summary>
/// The length of time, in milliseconds, before the running schedule task times out. Set null to use default value
/// </summary>
public int? ScheduleTaskRunTimeout { get; private set; } = null;
/// <summary>
/// Gets or sets a value of "Cache-Control" header value for static content (in seconds)
/// </summary>
public string StaticFilesCacheControl { get; private set; } = "public,max-age=31536000";
/// <summary>
/// Gets or sets a value indicating whether we should support previous nopCommerce versions (it can slightly improve performance)
/// </summary>
public bool SupportPreviousNopcommerceVersions { get; private set; } = true;
/// <summary>
/// Get or set the blacklist of static file extension for plugin directories
/// </summary>
public string PluginStaticFileExtensionsBlacklist { get; private set; } = "";
/// <summary>
/// Get or set a value indicating whether to serve files that don't have a recognized content-type
/// </summary>
/// <value></value>
public bool ServeUnknownFileTypes { get; private set; } = false;
}
}
@@ -0,0 +1,37 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents distributed cache configuration parameters
/// </summary>
public partial class DistributedCacheConfig : IConfig
{
/// <summary>
/// Gets or sets a distributed cache type
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public DistributedCacheType DistributedCacheType { get; private set; } = DistributedCacheType.Redis;
/// <summary>
/// Gets or sets a value indicating whether we should use distributed cache
/// </summary>
public bool Enabled { get; private set; } = false;
/// <summary>
/// Gets or sets connection string. Used when distributed cache is enabled
/// </summary>
public string ConnectionString { get; private set; } = "127.0.0.1:6379,ssl=False";
/// <summary>
/// Gets or sets schema name. Used when distributed cache is enabled and DistributedCacheType property is set as SqlServer
/// </summary>
public string SchemaName { get; private set; } = "dbo";
/// <summary>
/// Gets or sets table name. Used when distributed cache is enabled and DistributedCacheType property is set as SqlServer
/// </summary>
public string TableName { get; private set; } = "DistributedCache";
}
}
@@ -0,0 +1,17 @@
using System.Runtime.Serialization;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents distributed cache types enumeration
/// </summary>
public enum DistributedCacheType
{
[EnumMember(Value = "memory")]
Memory,
[EnumMember(Value = "sqlserver")]
SqlServer,
[EnumMember(Value = "redis")]
Redis
}
}
@@ -0,0 +1,29 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents hosting configuration parameters
/// </summary>
public partial class HostingConfig : IConfig
{
/// <summary>
/// Gets or sets a value indicating whether to use proxy servers and load balancers
/// </summary>
public bool UseProxy { get; private set; }
/// <summary>
/// Gets or sets the header used to retrieve the value for the originating scheme (HTTP/HTTPS)
/// </summary>
public string ForwardedProtoHeaderName { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets the header used to retrieve the originating client IP
/// </summary>
public string ForwardedForHeaderName { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets addresses of known proxies to accept forwarded headers from
/// </summary>
public string KnownProxies { get; private set; } = string.Empty;
}
}
@@ -0,0 +1,22 @@
using Newtonsoft.Json;
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents a configuration from app settings
/// </summary>
public partial interface IConfig
{
/// <summary>
/// Gets a section name to load configuration
/// </summary>
[JsonIgnore]
string Name => GetType().Name;
/// <summary>
/// Gets an order of configuration
/// </summary>
/// <returns>Order</returns>
public int GetOrder() => 1;
}
}
@@ -0,0 +1,9 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Setting interface
/// </summary>
public interface ISettings
{
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents installation configuration parameters
/// </summary>
public partial class InstallationConfig : IConfig
{
/// <summary>
/// Gets or sets a value indicating whether a store owner can install sample data during installation
/// </summary>
public bool DisableSampleData { get; private set; } = false;
/// <summary>
/// Gets or sets a list of plugins ignored during nopCommerce installation
/// </summary>
public string DisabledPlugins { get; private set; } = string.Empty;
/// <summary>
/// Gets or sets a value indicating whether to download and setup the regional language pack during installation
/// </summary>
public bool InstallRegionalResources { get; private set; } = true;
}
}
@@ -0,0 +1,13 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents default values related to configuration services
/// </summary>
public static partial class NopConfigurationDefaults
{
/// <summary>
/// Gets the path to file that contains app settings
/// </summary>
public static string AppSettingsFilePath => "App_Data/appsettings.json";
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Configuration
{
/// <summary>
/// Represents plugin configuration parameters
/// </summary>
public partial class PluginConfig : IConfig
{
/// <summary>
/// Gets or sets a value indicating whether to clear /Plugins/bin directory on application startup
/// </summary>
public bool ClearPluginShadowDirectoryOnStartup { get; private set; } = true;
/// <summary>
/// Gets or sets a value indicating whether to copy "locked" assemblies from /Plugins/bin directory to temporary subdirectories on application startup
/// </summary>
public bool CopyLockedPluginAssembilesToSubdirectoriesOnStartup { get; private set; } = false;
/// <summary>
/// Gets or sets a value indicating whether to load an assembly into the load-from context, bypassing some security checks.
/// </summary>
public bool UseUnsafeLoadAssembly { get; private set; } = true;
/// <summary>
/// Gets or sets a value indicating whether to copy plugins library to the /Plugins/bin directory on application startup
/// </summary>
public bool UsePluginsShadowCopy { get; private set; } = true;
}
}
@@ -0,0 +1,35 @@
using Nop.Core.Domain.Common;
namespace Nop.Core.Domain.Affiliates
{
/// <summary>
/// Represents an affiliate
/// </summary>
public partial class Affiliate : BaseEntity, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the address identifier
/// </summary>
public int AddressId { get; set; }
/// <summary>
/// Gets or sets the admin comment
/// </summary>
public string AdminComment { get; set; }
/// <summary>
/// Gets or sets the friendly name for generated affiliate URL (by default affiliate ID is used)
/// </summary>
public string FriendlyUrlName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is active
/// </summary>
public bool Active { get; set; }
}
}
@@ -0,0 +1,40 @@
using System;
namespace Nop.Core.Domain.Blogs
{
/// <summary>
/// Represents a blog comment
/// </summary>
public partial class BlogComment : BaseEntity
{
/// <summary>
/// Gets or sets the customer identifier
/// </summary>
public int CustomerId { get; set; }
/// <summary>
/// Gets or sets the comment text
/// </summary>
public string CommentText { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the comment is approved
/// </summary>
public bool IsApproved { get; set; }
/// <summary>
/// Gets or sets the store identifier
/// </summary>
public int StoreId { get; set; }
/// <summary>
/// Gets or sets the blog post identifier
/// </summary>
public int BlogPostId { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
}
}
@@ -0,0 +1,82 @@
using System;
using Nop.Core.Domain.Seo;
using Nop.Core.Domain.Stores;
namespace Nop.Core.Domain.Blogs
{
/// <summary>
/// Represents a blog post
/// </summary>
public partial class BlogPost : BaseEntity, ISlugSupported, IStoreMappingSupported
{
/// <summary>
/// Gets or sets the language identifier
/// </summary>
public int LanguageId { get; set; }
/// <summary>
/// Gets or sets the value indicating whether this blog post should be included in sitemap
/// </summary>
public bool IncludeInSitemap { get; set; }
/// <summary>
/// Gets or sets the blog post title
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets or sets the blog post body
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the blog post overview. If specified, then it's used on the blog page instead of the "Body"
/// </summary>
public string BodyOverview { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the blog post comments are allowed
/// </summary>
public bool AllowComments { get; set; }
/// <summary>
/// Gets or sets the blog tags
/// </summary>
public string Tags { get; set; }
/// <summary>
/// Gets or sets the blog post start date and time
/// </summary>
public DateTime? StartDateUtc { get; set; }
/// <summary>
/// Gets or sets the blog post end date and time
/// </summary>
public DateTime? EndDateUtc { get; set; }
/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }
/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }
/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is limited/restricted to certain stores
/// </summary>
public virtual bool LimitedToStores { get; set; }
/// <summary>
/// Gets or sets the date and time of entity creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Blogs
{
/// <summary>
/// Represents a blog post tag
/// </summary>
public partial class BlogPostTag
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the tagged product count
/// </summary>
public int BlogPostCount { get; set; }
}
}
@@ -0,0 +1,50 @@
using Nop.Core.Configuration;
namespace Nop.Core.Domain.Blogs
{
/// <summary>
/// Blog settings
/// </summary>
public class BlogSettings : ISettings
{
/// <summary>
/// Gets or sets a value indicating whether blog is enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Gets or sets the page size for posts
/// </summary>
public int PostsPageSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether not registered user can leave comments
/// </summary>
public bool AllowNotRegisteredUsersToLeaveComments { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to notify about new blog comments
/// </summary>
public bool NotifyAboutNewBlogComments { get; set; }
/// <summary>
/// Gets or sets a number of blog tags that appear in the tag cloud
/// </summary>
public int NumberOfTags { get; set; }
/// <summary>
/// Enable the blog RSS feed link in customers browser address bar
/// </summary>
public bool ShowHeaderRssUrl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether blog comments must be approved
/// </summary>
public bool BlogCommentsMustBeApproved { get; set; }
/// <summary>
/// Gets or sets a value indicating whether blog comments will be filtered per store
/// </summary>
public bool ShowBlogCommentsPerStore { get; set; }
}
}
@@ -0,0 +1,22 @@
namespace Nop.Core.Domain.Blogs
{
/// <summary>
/// Blog post comment approved event
/// </summary>
public class BlogCommentApprovedEvent
{
/// <summary>
/// Ctor
/// </summary>
/// <param name="blogComment">Blog comment</param>
public BlogCommentApprovedEvent(BlogComment blogComment)
{
BlogComment = blogComment;
}
/// <summary>
/// Blog post comment
/// </summary>
public BlogComment BlogComment { get; }
}
}
@@ -0,0 +1,58 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents an attribute control type
/// </summary>
public enum AttributeControlType
{
/// <summary>
/// Dropdown list
/// </summary>
DropdownList = 1,
/// <summary>
/// Radio list
/// </summary>
RadioList = 2,
/// <summary>
/// Checkboxes
/// </summary>
Checkboxes = 3,
/// <summary>
/// TextBox
/// </summary>
TextBox = 4,
/// <summary>
/// Multiline textbox
/// </summary>
MultilineTextbox = 10,
/// <summary>
/// Datepicker
/// </summary>
Datepicker = 20,
/// <summary>
/// File upload control
/// </summary>
FileUpload = 30,
/// <summary>
/// Color squares
/// </summary>
ColorSquares = 40,
/// <summary>
/// Image squares
/// </summary>
ImageSquares = 45,
/// <summary>
/// Read-only checkboxes
/// </summary>
ReadonlyCheckboxes = 50
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents an attribute value display type when out of stock
/// </summary>
public enum AttributeValueOutOfStockDisplayType
{
/// <summary>
/// Attribute value is visible, but cannot be interacted
/// </summary>
Disable,
/// <summary>
/// Attribute value is display always
/// </summary>
AlwaysDisplay
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents an attribute value type
/// </summary>
public enum AttributeValueType
{
/// <summary>
/// Simple attribute value
/// </summary>
Simple = 0,
/// <summary>
/// Associated to a product (used when configuring bundled products)
/// </summary>
AssociatedToProduct = 10,
}
}
@@ -0,0 +1,30 @@
using System;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a back in stock subscription
/// </summary>
public partial class BackInStockSubscription : BaseEntity
{
/// <summary>
/// Gets or sets the store identifier
/// </summary>
public int StoreId { get; set; }
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the customer identifier
/// </summary>
public int CustomerId { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a backorder mode
/// </summary>
public enum BackorderMode
{
/// <summary>
/// No backorders
/// </summary>
NoBackorders = 0,
/// <summary>
/// Allow qty below 0
/// </summary>
AllowQtyBelow0 = 1,
/// <summary>
/// Allow qty below 0 and notify customer
/// </summary>
AllowQtyBelow0AndNotifyCustomer = 2,
}
}
@@ -0,0 +1,538 @@
using System.Collections.Generic;
using Nop.Core.Configuration;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Catalog settings
/// </summary>
public class CatalogSettings : ISettings
{
public CatalogSettings()
{
ProductSortingEnumDisabled = new List<int>();
ProductSortingEnumDisplayOrder = new Dictionary<int, int>();
}
/// <summary>
/// Gets or sets a value indicating details pages of unpublished product details pages could be open (for SEO optimization)
/// </summary>
public bool AllowViewUnpublishedProductPage { get; set; }
/// <summary>
/// Gets or sets a value indicating customers should see "discontinued" message when visiting details pages of unpublished products (if "AllowViewUnpublishedProductPage" is "true)
/// </summary>
public bool DisplayDiscontinuedMessageForUnpublishedProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "Published" or "Disable buy/wishlist buttons" flags should be updated after order cancellation (deletion).
/// Of course, when qty > configured minimum stock level
/// </summary>
public bool PublishBackProductWhenCancellingOrders { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display product SKU on the product details page
/// </summary>
public bool ShowSkuOnProductDetailsPage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display product SKU on catalog pages
/// </summary>
public bool ShowSkuOnCatalogPages { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display manufacturer part number of a product
/// </summary>
public bool ShowManufacturerPartNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display GTIN of a product
/// </summary>
public bool ShowGtin { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "Free shipping" icon should be displayed for products
/// </summary>
public bool ShowFreeShippingNotification { get; set; }
/// <summary>
/// Gets or sets a value indicating whether product sorting is enabled
/// </summary>
public bool AllowProductSorting { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers are allowed to change product view mode
/// </summary>
public bool AllowProductViewModeChanging { get; set; }
/// <summary>
/// Gets or sets a default view mode
/// </summary>
public string DefaultViewMode { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a category details page should include products from subcategories
/// </summary>
public bool ShowProductsFromSubcategories { get; set; }
/// <summary>
/// Gets or sets a value indicating whether number of products should be displayed beside each category
/// </summary>
public bool ShowCategoryProductNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether we include subcategories (when 'ShowCategoryProductNumber' is 'true')
/// </summary>
public bool ShowCategoryProductNumberIncludingSubcategories { get; set; }
/// <summary>
/// Gets or sets a value indicating whether category breadcrumb is enabled
/// </summary>
public bool CategoryBreadcrumbEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a 'Share button' is enabled
/// </summary>
public bool ShowShareButton { get; set; }
/// <summary>
/// Gets or sets a share code (e.g. AddThis button code)
/// </summary>
public string PageShareCode { get; set; }
/// <summary>
/// Gets or sets a value indicating product reviews must be approved
/// </summary>
public bool ProductReviewsMustBeApproved { get; set; }
/// <summary>
/// Gets or sets a value indicating that customer can add only one review per product
/// </summary>
public bool OneReviewPerProductFromCustomer { get; set; }
/// <summary>
/// Gets or sets a value indicating the default rating value of the product reviews
/// </summary>
public int DefaultProductRatingValue { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to allow anonymous users write product reviews.
/// </summary>
public bool AllowAnonymousUsersToReviewProduct { get; set; }
/// <summary>
/// Gets or sets a value indicating whether product can be reviewed only by customer who have already ordered it
/// </summary>
public bool ProductReviewPossibleOnlyAfterPurchasing { get; set; }
/// <summary>
/// Gets or sets a value indicating whether notification of a store owner about new product reviews is enabled
/// </summary>
public bool NotifyStoreOwnerAboutNewProductReviews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customer notification about product review reply is enabled
/// </summary>
public bool NotifyCustomerAboutProductReviewReply { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product reviews will be filtered per store
/// </summary>
public bool ShowProductReviewsPerStore { get; set; }
/// <summary>
/// Gets or sets a show product reviews tab on account page
/// </summary>
public bool ShowProductReviewsTabOnAccountPage { get; set; }
/// <summary>
/// Gets or sets the page size for product reviews in account page
/// </summary>
public int ProductReviewsPageSizeOnAccountPage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product reviews should be sorted by creation date as ascending
/// </summary>
public bool ProductReviewsSortByCreatedDateAscending { get; set; }
/// <summary>
/// Gets or sets a value indicating whether product 'Email a friend' feature is enabled
/// </summary>
public bool EmailAFriendEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to allow anonymous users to email a friend.
/// </summary>
public bool AllowAnonymousUsersToEmailAFriend { get; set; }
/// <summary>
/// Gets or sets a number of "Recently viewed products"
/// </summary>
public int RecentlyViewedProductsNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "Recently viewed products" feature is enabled
/// </summary>
public bool RecentlyViewedProductsEnabled { get; set; }
/// <summary>
/// Gets or sets a number of products on the "New products" page
/// </summary>
public int NewProductsNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "New products" page is enabled
/// </summary>
public bool NewProductsEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "Compare products" feature is enabled
/// </summary>
public bool CompareProductsEnabled { get; set; }
/// <summary>
/// Gets or sets an allowed number of products to be compared
/// </summary>
public int CompareProductsNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether autocomplete is enabled
/// </summary>
public bool ProductSearchAutoCompleteEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the search box is displayed
/// </summary>
public bool ProductSearchEnabled { get; set; }
/// <summary>
/// Gets or sets a number of products to return when using "autocomplete" feature
/// </summary>
public int ProductSearchAutoCompleteNumberOfProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show product images in the auto complete search
/// </summary>
public bool ShowProductImagesInSearchAutoComplete { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show link to all result in the auto complete search
/// </summary>
public bool ShowLinkToAllResultInSearchAutoComplete { get; set; }
/// <summary>
/// Gets or sets a minimum search term length
/// </summary>
public int ProductSearchTermMinimumLength { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show bestsellers on home page
/// </summary>
public bool ShowBestsellersOnHomepage { get; set; }
/// <summary>
/// Gets or sets a number of bestsellers on home page
/// </summary>
public int NumberOfBestsellersOnHomepage { get; set; }
/// <summary>
/// Gets or sets a number of products per page on the search products page
/// </summary>
public int SearchPageProductsPerPage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers are allowed to select page size on the search products page
/// </summary>
public bool SearchPageAllowCustomersToSelectPageSize { get; set; }
/// <summary>
/// Gets or sets the available customer selectable page size options on the search products page
/// </summary>
public string SearchPagePageSizeOptions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled on search page
/// </summary>
public bool SearchPagePriceRangeFiltering { get; set; }
/// <summary>
/// Gets or sets the "from" price on search page
/// </summary>
public decimal SearchPagePriceFrom { get; set; }
/// <summary>
/// Gets or sets the "to" price on search page
/// </summary>
public decimal SearchPagePriceTo { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually on search page
/// </summary>
public bool SearchPageManuallyPriceRange { get; set; }
/// <summary>
/// Gets or sets "List of products purchased by other customers who purchased the above" option is enable
/// </summary>
public bool ProductsAlsoPurchasedEnabled { get; set; }
/// <summary>
/// Gets or sets a number of products also purchased by other customers to display
/// </summary>
public int ProductsAlsoPurchasedNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether we should process attribute change using AJAX. It's used for dynamical attribute change, SKU/GTIN update of combinations, conditional attributes
/// </summary>
public bool AjaxProcessAttributeChange { get; set; }
/// <summary>
/// Gets or sets a number of product tags that appear in the tag cloud
/// </summary>
public int NumberOfProductTags { get; set; }
/// <summary>
/// Gets or sets a number of products per page on 'products by tag' page
/// </summary>
public int ProductsByTagPageSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers can select the page size for 'products by tag'
/// </summary>
public bool ProductsByTagAllowCustomersToSelectPageSize { get; set; }
/// <summary>
/// Gets or sets the available customer selectable page size options for 'products by tag'
/// </summary>
public string ProductsByTagPageSizeOptions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled on 'products by tag' page
/// </summary>
public bool ProductsByTagPriceRangeFiltering { get; set; }
/// <summary>
/// Gets or sets the "from" price on 'products by tag' page
/// </summary>
public decimal ProductsByTagPriceFrom { get; set; }
/// <summary>
/// Gets or sets the "to" price on 'products by tag' page
/// </summary>
public decimal ProductsByTagPriceTo { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually on 'products by tag' page
/// </summary>
public bool ProductsByTagManuallyPriceRange { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to include "Short description" in compare products
/// </summary>
public bool IncludeShortDescriptionInCompareProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to include "Full description" in compare products
/// </summary>
public bool IncludeFullDescriptionInCompareProducts { get; set; }
/// <summary>
/// An option indicating whether products on category and manufacturer pages should include featured products as well
/// </summary>
public bool IncludeFeaturedProductsInNormalLists { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to render link to required products in "Require other products added to the cart" warning
/// </summary>
public bool UseLinksInRequiredProductWarnings { get; set; }
/// <summary>
/// Gets or sets a value indicating whether tier prices should be displayed with applied discounts (if available)
/// </summary>
public bool DisplayTierPricesWithDiscounts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to ignore discounts (side-wide). It can significantly improve performance when enabled.
/// </summary>
public bool IgnoreDiscounts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to ignore featured products (side-wide). It can significantly improve performance when enabled.
/// </summary>
public bool IgnoreFeaturedProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to ignore ACL rules (side-wide). It can significantly improve performance when enabled.
/// </summary>
public bool IgnoreAcl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to ignore "limit per store" rules (side-wide). It can significantly improve performance when enabled.
/// </summary>
public bool IgnoreStoreLimitations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to cache product prices. It can significantly improve performance when enabled.
/// </summary>
public bool CacheProductPrices { get; set; }
/// <summary>
/// Gets or sets a value indicating maximum number of 'back in stock' subscription
/// </summary>
public int MaximumBackInStockSubscriptions { get; set; }
/// <summary>
/// Gets or sets the value indicating how many manufacturers to display in manufacturers block
/// </summary>
public int ManufacturersBlockItemsToDisplay { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax in the footer (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoFooter { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax on product details pages (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoProductDetailsPage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax in product boxes (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoProductBoxes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax on shopping cart page (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoShoppingCart { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax on wishlist page (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoWishlist { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display information about shipping and tax on order details page (used in Germany)
/// </summary>
public bool DisplayTaxShippingInfoOrderDetailsPage { get; set; }
/// <summary>
/// Gets or sets the default value to use for Category page size options (for new categories)
/// </summary>
public string DefaultCategoryPageSizeOptions { get; set; }
/// <summary>
/// Gets or sets the default value to use for Category page size (for new categories)
/// </summary>
public int DefaultCategoryPageSize { get; set; }
/// <summary>
/// Gets or sets the default value to use for Manufacturer page size options (for new manufacturers)
/// </summary>
public string DefaultManufacturerPageSizeOptions { get; set; }
/// <summary>
/// Gets or sets the default value to use for Manufacturer page size (for new manufacturers)
/// </summary>
public int DefaultManufacturerPageSize { get; set; }
/// <summary>
/// Gets or sets a list of disabled values of ProductSortingEnum
/// </summary>
public List<int> ProductSortingEnumDisabled { get; set; }
/// <summary>
/// Gets or sets a display order of ProductSortingEnum values
/// </summary>
public Dictionary<int, int> ProductSortingEnumDisplayOrder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the products need to be exported/imported with their attributes
/// </summary>
public bool ExportImportProductAttributes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether need to use "limited to stores" property for exported/imported products
/// </summary>
public bool ExportImportProductUseLimitedToStores { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the products need to be exported/imported with their specification attributes
/// </summary>
public bool ExportImportProductSpecificationAttributes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether need create dropdown list for export
/// </summary>
public bool ExportImportUseDropdownlistsForAssociatedEntities { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the products should be exported/imported with a full category name including names of all its parents
/// </summary>
public bool ExportImportProductCategoryBreadcrumb { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the categories need to be exported/imported using name of category
/// </summary>
public bool ExportImportCategoriesUsingCategoryName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the images can be downloaded from remote server
/// </summary>
public bool ExportImportAllowDownloadImages { get; set; }
/// <summary>
/// Gets or sets a value indicating whether products must be importing by separated files
/// </summary>
public bool ExportImportSplitProductsFile { get; set; }
/// <summary>
/// Gets or sets a value of max products count in one file
/// </summary>
public int ExportImportProductsCountInOneFile { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to remove required products from the cart if the main one is removed
/// </summary>
public bool RemoveRequiredProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the related entities need to be exported/imported using name
/// </summary>
public bool ExportImportRelatedEntitiesByName { get; set; }
/// <summary>
/// Gets or sets count of displayed years for datepicker
/// </summary>
public int CountDisplayedYearsDatePicker { get; set; }
/// <summary>
/// Get or set a value indicating whether it's necessary to show the date for pre-order availability in a public store
/// </summary>
public bool DisplayDatePreOrderAvailability { get; set; }
/// <summary>
/// Get or set a value indicating whether use standart menu in public store or use Ajax to load menu
/// </summary>
public bool UseAjaxLoadMenu { get; set; }
/// <summary>
/// Get or set a value indicating whether use standart or AJAX products loading (applicable to 'paging', 'filtering', 'view modes') in catalog
/// </summary>
public bool UseAjaxCatalogProductsLoading { get; set; }
/// <summary>
/// Get or set a value indicating whether the manufacturer filtering is enabled on catalog pages
/// </summary>
public bool EnableManufacturerFiltering { get; set; }
/// <summary>
/// Get or set a value indicating whether the price range filtering is enabled on catalog pages
/// </summary>
public bool EnablePriceRangeFiltering { get; set; }
/// <summary>
/// Gets or sets the attribute value display type when out of stock
/// </summary>
public AttributeValueOutOfStockDisplayType AttributeValueOutOfStockDisplayType { get; set; }
}
}
@@ -0,0 +1,136 @@
using System;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Security;
using Nop.Core.Domain.Seo;
using Nop.Core.Domain.Stores;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a category
/// </summary>
public partial class Category : BaseEntity, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IDiscountSupported<DiscountCategoryMapping>, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }
/// <summary>
/// Gets or sets a value of used category template identifier
/// </summary>
public int CategoryTemplateId { get; set; }
/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }
/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }
/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }
/// <summary>
/// Gets or sets the parent category identifier
/// </summary>
public int ParentCategoryId { get; set; }
/// <summary>
/// Gets or sets the picture identifier
/// </summary>
public int PictureId { get; set; }
/// <summary>
/// Gets or sets the page size
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers can select the page size
/// </summary>
public bool AllowCustomersToSelectPageSize { get; set; }
/// <summary>
/// Gets or sets the available customer selectable page size options
/// </summary>
public string PageSizeOptions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show the category on home page
/// </summary>
public bool ShowOnHomepage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to include this category in the top menu
/// </summary>
public bool IncludeInTopMenu { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is subject to ACL
/// </summary>
public bool SubjectToAcl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is limited/restricted to certain stores
/// </summary>
public bool LimitedToStores { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is published
/// </summary>
public bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the date and time of instance update
/// </summary>
public DateTime UpdatedOnUtc { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled
/// </summary>
public bool PriceRangeFiltering { get; set; }
/// <summary>
/// Gets or sets the "from" price
/// </summary>
public decimal PriceFrom { get; set; }
/// <summary>
/// Gets or sets the "to" price
/// </summary>
public decimal PriceTo { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually
/// </summary>
public bool ManuallyPriceRange { get; set; }
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a category template
/// </summary>
public partial class CategoryTemplate : BaseEntity
{
/// <summary>
/// Gets or sets the template name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the view path
/// </summary>
public string ViewPath { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a cross-sell product
/// </summary>
public partial class CrossSellProduct : BaseEntity
{
/// <summary>
/// Gets or sets the first product identifier
/// </summary>
public int ProductId1 { get; set; }
/// <summary>
/// Gets or sets the second product identifier
/// </summary>
public int ProductId2 { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a download activation type
/// </summary>
public enum DownloadActivationType
{
/// <summary>
/// When order is paid
/// </summary>
WhenOrderIsPaid = 0,
/// <summary>
/// Manually
/// </summary>
Manually = 10,
}
}
@@ -0,0 +1,22 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Product review approved event
/// </summary>
public class ProductReviewApprovedEvent
{
/// <summary>
/// Ctor
/// </summary>
/// <param name="productReview">Product review</param>
public ProductReviewApprovedEvent(ProductReview productReview)
{
ProductReview = productReview;
}
/// <summary>
/// Product review
/// </summary>
public ProductReview ProductReview { get; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a gift card type
/// </summary>
public enum GiftCardType
{
/// <summary>
/// Virtual
/// </summary>
Virtual = 0,
/// <summary>
/// Physical
/// </summary>
Physical = 1,
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a low stock activity
/// </summary>
public enum LowStockActivity
{
/// <summary>
/// Nothing
/// </summary>
Nothing = 0,
/// <summary>
/// Disable buy button
/// </summary>
DisableBuyButton = 1,
/// <summary>
/// Unpublish
/// </summary>
Unpublish = 2,
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a method of inventory management
/// </summary>
public enum ManageInventoryMethod
{
/// <summary>
/// Don't track inventory for product
/// </summary>
DontManageStock = 0,
/// <summary>
/// Track inventory for product
/// </summary>
ManageStock = 1,
/// <summary>
/// Track inventory for product by product attributes
/// </summary>
ManageStockByAttributes = 2,
}
}
@@ -0,0 +1,121 @@
using System;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Security;
using Nop.Core.Domain.Seo;
using Nop.Core.Domain.Stores;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a manufacturer
/// </summary>
public partial class Manufacturer : BaseEntity, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IDiscountSupported<DiscountManufacturerMapping>, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }
/// <summary>
/// Gets or sets a value of used manufacturer template identifier
/// </summary>
public int ManufacturerTemplateId { get; set; }
/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }
/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }
/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }
/// <summary>
/// Gets or sets the parent picture identifier
/// </summary>
public int PictureId { get; set; }
/// <summary>
/// Gets or sets the page size
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers can select the page size
/// </summary>
public bool AllowCustomersToSelectPageSize { get; set; }
/// <summary>
/// Gets or sets the available customer selectable page size options
/// </summary>
public string PageSizeOptions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is subject to ACL
/// </summary>
public bool SubjectToAcl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is limited/restricted to certain stores
/// </summary>
public bool LimitedToStores { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is published
/// </summary>
public bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the date and time of instance update
/// </summary>
public DateTime UpdatedOnUtc { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled
/// </summary>
public bool PriceRangeFiltering { get; set; }
/// <summary>
/// Gets or sets the "from" price
/// </summary>
public decimal PriceFrom { get; set; }
/// <summary>
/// Gets or sets the "to" price
/// </summary>
public decimal PriceTo { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually
/// </summary>
public bool ManuallyPriceRange { get; set; }
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a manufacturer template
/// </summary>
public partial class ManufacturerTemplate : BaseEntity
{
/// <summary>
/// Gets or sets the template name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the view path
/// </summary>
public string ViewPath { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,50 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a predefined (default) product attribute value
/// </summary>
public partial class PredefinedProductAttributeValue : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the product attribute identifier
/// </summary>
public int ProductAttributeId { get; set; }
/// <summary>
/// Gets or sets the product attribute name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the price adjustment
/// </summary>
public decimal PriceAdjustment { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "price adjustment" is specified as percentage
/// </summary>
public bool PriceAdjustmentUsePercentage { get; set; }
/// <summary>
/// Gets or sets the weight adjustment
/// </summary>
public decimal WeightAdjustment { get; set; }
/// <summary>
/// Gets or sets the attribute value cost
/// </summary>
public decimal Cost { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the value is pre-selected
/// </summary>
public bool IsPreSelected { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,616 @@
using System;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Security;
using Nop.Core.Domain.Seo;
using Nop.Core.Domain.Stores;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product
/// </summary>
public partial class Product : BaseEntity, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IDiscountSupported<DiscountProductMapping>, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the product type identifier
/// </summary>
public int ProductTypeId { get; set; }
/// <summary>
/// Gets or sets the parent product identifier. It's used to identify associated products (only with "grouped" products)
/// </summary>
public int ParentGroupedProductId { get; set; }
/// <summary>
/// Gets or sets the values indicating whether this product is visible in catalog or search results.
/// It's used when this product is associated to some "grouped" one
/// This way associated products could be accessed/added/etc only from a grouped product details page
/// </summary>
public bool VisibleIndividually { get; set; }
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the short description
/// </summary>
public string ShortDescription { get; set; }
/// <summary>
/// Gets or sets the full description
/// </summary>
public string FullDescription { get; set; }
/// <summary>
/// Gets or sets the admin comment
/// </summary>
public string AdminComment { get; set; }
/// <summary>
/// Gets or sets a value of used product template identifier
/// </summary>
public int ProductTemplateId { get; set; }
/// <summary>
/// Gets or sets a vendor identifier
/// </summary>
public int VendorId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show the product on home page
/// </summary>
public bool ShowOnHomepage { get; set; }
/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }
/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }
/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product allows customer reviews
/// </summary>
public bool AllowCustomerReviews { get; set; }
/// <summary>
/// Gets or sets the rating sum (approved reviews)
/// </summary>
public int ApprovedRatingSum { get; set; }
/// <summary>
/// Gets or sets the rating sum (not approved reviews)
/// </summary>
public int NotApprovedRatingSum { get; set; }
/// <summary>
/// Gets or sets the total rating votes (approved reviews)
/// </summary>
public int ApprovedTotalReviews { get; set; }
/// <summary>
/// Gets or sets the total rating votes (not approved reviews)
/// </summary>
public int NotApprovedTotalReviews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is subject to ACL
/// </summary>
public bool SubjectToAcl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is limited/restricted to certain stores
/// </summary>
public bool LimitedToStores { get; set; }
/// <summary>
/// Gets or sets the SKU
/// </summary>
public string Sku { get; set; }
/// <summary>
/// Gets or sets the manufacturer part number
/// </summary>
public string ManufacturerPartNumber { get; set; }
/// <summary>
/// Gets or sets the Global Trade Item Number (GTIN). These identifiers include UPC (in North America), EAN (in Europe), JAN (in Japan), and ISBN (for books).
/// </summary>
public string Gtin { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is gift card
/// </summary>
public bool IsGiftCard { get; set; }
/// <summary>
/// Gets or sets the gift card type identifier
/// </summary>
public int GiftCardTypeId { get; set; }
/// <summary>
/// Gets or sets gift card amount that can be used after purchase. If not specified, then product price will be used.
/// </summary>
public decimal? OverriddenGiftCardAmount { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product requires that other products are added to the cart (Product X requires Product Y)
/// </summary>
public bool RequireOtherProducts { get; set; }
/// <summary>
/// Gets or sets a required product identifiers (comma separated)
/// </summary>
public string RequiredProductIds { get; set; }
/// <summary>
/// Gets or sets a value indicating whether required products are automatically added to the cart
/// </summary>
public bool AutomaticallyAddRequiredProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is download
/// </summary>
public bool IsDownload { get; set; }
/// <summary>
/// Gets or sets the download identifier
/// </summary>
public int DownloadId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this downloadable product can be downloaded unlimited number of times
/// </summary>
public bool UnlimitedDownloads { get; set; }
/// <summary>
/// Gets or sets the maximum number of downloads
/// </summary>
public int MaxNumberOfDownloads { get; set; }
/// <summary>
/// Gets or sets the number of days during customers keeps access to the file.
/// </summary>
public int? DownloadExpirationDays { get; set; }
/// <summary>
/// Gets or sets the download activation type
/// </summary>
public int DownloadActivationTypeId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product has a sample download file
/// </summary>
public bool HasSampleDownload { get; set; }
/// <summary>
/// Gets or sets the sample download identifier
/// </summary>
public int SampleDownloadId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product has user agreement
/// </summary>
public bool HasUserAgreement { get; set; }
/// <summary>
/// Gets or sets the text of license agreement
/// </summary>
public string UserAgreementText { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is recurring
/// </summary>
public bool IsRecurring { get; set; }
/// <summary>
/// Gets or sets the cycle length
/// </summary>
public int RecurringCycleLength { get; set; }
/// <summary>
/// Gets or sets the cycle period
/// </summary>
public int RecurringCyclePeriodId { get; set; }
/// <summary>
/// Gets or sets the total cycles
/// </summary>
public int RecurringTotalCycles { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is rental
/// </summary>
public bool IsRental { get; set; }
/// <summary>
/// Gets or sets the rental length for some period (price for this period)
/// </summary>
public int RentalPriceLength { get; set; }
/// <summary>
/// Gets or sets the rental period (price for this period)
/// </summary>
public int RentalPricePeriodId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is ship enabled
/// </summary>
public bool IsShipEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is free shipping
/// </summary>
public bool IsFreeShipping { get; set; }
/// <summary>
/// Gets or sets a value this product should be shipped separately (each item)
/// </summary>
public bool ShipSeparately { get; set; }
/// <summary>
/// Gets or sets the additional shipping charge
/// </summary>
public decimal AdditionalShippingCharge { get; set; }
/// <summary>
/// Gets or sets a delivery date identifier
/// </summary>
public int DeliveryDateId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is marked as tax exempt
/// </summary>
public bool IsTaxExempt { get; set; }
/// <summary>
/// Gets or sets the tax category identifier
/// </summary>
public int TaxCategoryId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is telecommunications or broadcasting or electronic services
/// </summary>
public bool IsTelecommunicationsOrBroadcastingOrElectronicServices { get; set; }
/// <summary>
/// Gets or sets a value indicating how to manage inventory
/// </summary>
public int ManageInventoryMethodId { get; set; }
/// <summary>
/// Gets or sets a product availability range identifier
/// </summary>
public int ProductAvailabilityRangeId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether multiple warehouses are used for this product
/// </summary>
public bool UseMultipleWarehouses { get; set; }
/// <summary>
/// Gets or sets a warehouse identifier
/// </summary>
public int WarehouseId { get; set; }
/// <summary>
/// Gets or sets the stock quantity
/// </summary>
public int StockQuantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display stock availability
/// </summary>
public bool DisplayStockAvailability { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display stock quantity
/// </summary>
public bool DisplayStockQuantity { get; set; }
/// <summary>
/// Gets or sets the minimum stock quantity
/// </summary>
public int MinStockQuantity { get; set; }
/// <summary>
/// Gets or sets the low stock activity identifier
/// </summary>
public int LowStockActivityId { get; set; }
/// <summary>
/// Gets or sets the quantity when admin should be notified
/// </summary>
public int NotifyAdminForQuantityBelow { get; set; }
/// <summary>
/// Gets or sets a value backorder mode identifier
/// </summary>
public int BackorderModeId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to back in stock subscriptions are allowed
/// </summary>
public bool AllowBackInStockSubscriptions { get; set; }
/// <summary>
/// Gets or sets the order minimum quantity
/// </summary>
public int OrderMinimumQuantity { get; set; }
/// <summary>
/// Gets or sets the order maximum quantity
/// </summary>
public int OrderMaximumQuantity { get; set; }
/// <summary>
/// Gets or sets the comma separated list of allowed quantities. null or empty if any quantity is allowed
/// </summary>
public string AllowedQuantities { get; set; }
/// <summary>
/// Gets or sets a value indicating whether we allow adding to the cart/wishlist only attribute combinations that exist and have stock greater than zero.
/// This option is used only when we have "manage inventory" set to "track inventory by product attributes"
/// </summary>
public bool AllowAddingOnlyExistingAttributeCombinations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this product is returnable (a customer is allowed to submit return request with this product)
/// </summary>
public bool NotReturnable { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to disable buy (Add to cart) button
/// </summary>
public bool DisableBuyButton { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to disable "Add to wishlist" button
/// </summary>
public bool DisableWishlistButton { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this item is available for Pre-Order
/// </summary>
public bool AvailableForPreOrder { get; set; }
/// <summary>
/// Gets or sets the start date and time of the product availability (for pre-order products)
/// </summary>
public DateTime? PreOrderAvailabilityStartDateTimeUtc { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to show "Call for Pricing" or "Call for quote" instead of price
/// </summary>
public bool CallForPrice { get; set; }
/// <summary>
/// Gets or sets the price
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// Gets or sets the old price
/// </summary>
public decimal OldPrice { get; set; }
/// <summary>
/// Gets or sets the product cost
/// </summary>
public decimal ProductCost { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a customer enters price
/// </summary>
public bool CustomerEntersPrice { get; set; }
/// <summary>
/// Gets or sets the minimum price entered by a customer
/// </summary>
public decimal MinimumCustomerEnteredPrice { get; set; }
/// <summary>
/// Gets or sets the maximum price entered by a customer
/// </summary>
public decimal MaximumCustomerEnteredPrice { get; set; }
/// <summary>
/// Gets or sets a value indicating whether base price (PAngV) is enabled. Used by German users.
/// </summary>
public bool BasepriceEnabled { get; set; }
/// <summary>
/// Gets or sets an amount in product for PAngV
/// </summary>
public decimal BasepriceAmount { get; set; }
/// <summary>
/// Gets or sets a unit of product for PAngV (MeasureWeight entity)
/// </summary>
public int BasepriceUnitId { get; set; }
/// <summary>
/// Gets or sets a reference amount for PAngV
/// </summary>
public decimal BasepriceBaseAmount { get; set; }
/// <summary>
/// Gets or sets a reference unit for PAngV (MeasureWeight entity)
/// </summary>
public int BasepriceBaseUnitId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this product is marked as new
/// </summary>
public bool MarkAsNew { get; set; }
/// <summary>
/// Gets or sets the start date and time of the new product (set product as "New" from date). Leave empty to ignore this property
/// </summary>
public DateTime? MarkAsNewStartDateTimeUtc { get; set; }
/// <summary>
/// Gets or sets the end date and time of the new product (set product as "New" to date). Leave empty to ignore this property
/// </summary>
public DateTime? MarkAsNewEndDateTimeUtc { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this product has tier prices configured
/// <remarks>The same as if we run TierPrices.Count > 0
/// We use this property for performance optimization:
/// if this property is set to false, then we do not need to load tier prices navigation property
/// </remarks>
/// </summary>
public bool HasTierPrices { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this product has discounts applied
/// <remarks>The same as if we run AppliedDiscounts.Count > 0
/// We use this property for performance optimization:
/// if this property is set to false, then we do not need to load Applied Discounts navigation property
/// </remarks>
/// </summary>
public bool HasDiscountsApplied { get; set; }
/// <summary>
/// Gets or sets the weight
/// </summary>
public decimal Weight { get; set; }
/// <summary>
/// Gets or sets the length
/// </summary>
public decimal Length { get; set; }
/// <summary>
/// Gets or sets the width
/// </summary>
public decimal Width { get; set; }
/// <summary>
/// Gets or sets the height
/// </summary>
public decimal Height { get; set; }
/// <summary>
/// Gets or sets the available start date and time
/// </summary>
public DateTime? AvailableStartDateTimeUtc { get; set; }
/// <summary>
/// Gets or sets the available end date and time
/// </summary>
public DateTime? AvailableEndDateTimeUtc { get; set; }
/// <summary>
/// Gets or sets a display order.
/// This value is used when sorting associated products (used with "grouped" products)
/// This value is used when sorting home page products
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is published
/// </summary>
public bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }
/// <summary>
/// Gets or sets the date and time of product creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the date and time of product update
/// </summary>
public DateTime UpdatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the product type
/// </summary>
public ProductType ProductType
{
get => (ProductType)ProductTypeId;
set => ProductTypeId = (int)value;
}
/// <summary>
/// Gets or sets the backorder mode
/// </summary>
public BackorderMode BackorderMode
{
get => (BackorderMode)BackorderModeId;
set => BackorderModeId = (int)value;
}
/// <summary>
/// Gets or sets the download activation type
/// </summary>
public DownloadActivationType DownloadActivationType
{
get => (DownloadActivationType)DownloadActivationTypeId;
set => DownloadActivationTypeId = (int)value;
}
/// <summary>
/// Gets or sets the gift card type
/// </summary>
public GiftCardType GiftCardType
{
get => (GiftCardType)GiftCardTypeId;
set => GiftCardTypeId = (int)value;
}
/// <summary>
/// Gets or sets the low stock activity
/// </summary>
public LowStockActivity LowStockActivity
{
get => (LowStockActivity)LowStockActivityId;
set => LowStockActivityId = (int)value;
}
/// <summary>
/// Gets or sets the value indicating how to manage inventory
/// </summary>
public ManageInventoryMethod ManageInventoryMethod
{
get => (ManageInventoryMethod)ManageInventoryMethodId;
set => ManageInventoryMethodId = (int)value;
}
/// <summary>
/// Gets or sets the cycle period for recurring products
/// </summary>
public RecurringProductCyclePeriod RecurringCyclePeriod
{
get => (RecurringProductCyclePeriod)RecurringCyclePeriodId;
set => RecurringCyclePeriodId = (int)value;
}
/// <summary>
/// Gets or sets the period for rental products
/// </summary>
public RentalPricePeriod RentalPricePeriod
{
get => (RentalPricePeriod)RentalPricePeriodId;
set => RentalPricePeriodId = (int)value;
}
}
}
@@ -0,0 +1,20 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product attribute
/// </summary>
public partial class ProductAttribute : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }
}
}
@@ -0,0 +1,63 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product attribute combination
/// </summary>
public partial class ProductAttributeCombination : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the attributes
/// </summary>
public string AttributesXml { get; set; }
/// <summary>
/// Gets or sets the stock quantity
/// </summary>
public int StockQuantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to allow orders when out of stock
/// </summary>
public bool AllowOutOfStockOrders { get; set; }
/// <summary>
/// Gets or sets the SKU
/// </summary>
public string Sku { get; set; }
/// <summary>
/// Gets or sets the manufacturer part number
/// </summary>
public string ManufacturerPartNumber { get; set; }
/// <summary>
/// Gets or sets the Global Trade Item Number (GTIN). These identifiers include UPC (in North America), EAN (in Europe), JAN (in Japan), and ISBN (for books).
/// </summary>
public string Gtin { get; set; }
/// <summary>
/// Gets or sets the attribute combination price. This way a store owner can override the default product price when this attribute combination is added to the cart. For example, you can give a discount this way.
/// </summary>
public decimal? OverriddenPrice { get; set; }
/// <summary>
/// Gets or sets the quantity when admin should be notified
/// </summary>
public int NotifyAdminForQuantityBelow { get; set; }
/// <summary>
/// Gets or sets the identifier of picture associated with this combination
/// </summary>
public int PictureId { get; set; }
/// <summary>
/// Gets or sets the minimum stock quantity
/// </summary>
public int MinStockQuantity { get; set; }
}
}
@@ -0,0 +1,84 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product attribute mapping
/// </summary>
public partial class ProductAttributeMapping : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the product attribute identifier
/// </summary>
public int ProductAttributeId { get; set; }
/// <summary>
/// Gets or sets a value a text prompt
/// </summary>
public string TextPrompt { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is required
/// </summary>
public bool IsRequired { get; set; }
/// <summary>
/// Gets or sets the attribute control type identifier
/// </summary>
public int AttributeControlTypeId { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
//validation fields
/// <summary>
/// Gets or sets the validation rule for minimum length (for textbox and multiline textbox)
/// </summary>
public int? ValidationMinLength { get; set; }
/// <summary>
/// Gets or sets the validation rule for maximum length (for textbox and multiline textbox)
/// </summary>
public int? ValidationMaxLength { get; set; }
/// <summary>
/// Gets or sets the validation rule for file allowed extensions (for file upload)
/// </summary>
public string ValidationFileAllowedExtensions { get; set; }
/// <summary>
/// Gets or sets the validation rule for file maximum size in kilobytes (for file upload)
/// </summary>
public int? ValidationFileMaximumSize { get; set; }
/// <summary>
/// Gets or sets the default value (for textbox and multiline textbox)
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// Gets or sets a condition (depending on other attribute) when this attribute should be enabled (visible).
/// Leave empty (or null) to enable this attribute.
/// Conditional attributes that only appear if a previous attribute is selected, such as having an option
/// for personalizing clothing with a name and only providing the text input box if the "Personalize" radio button is checked.
/// </summary>
public string ConditionAttributeXml { get; set; }
/// <summary>
/// Gets the attribute control type
/// </summary>
public AttributeControlType AttributeControlType
{
get => (AttributeControlType)AttributeControlTypeId;
set => AttributeControlTypeId = (int)value;
}
}
}
@@ -0,0 +1,94 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product attribute value
/// </summary>
public partial class ProductAttributeValue : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the product attribute mapping identifier
/// </summary>
public int ProductAttributeMappingId { get; set; }
/// <summary>
/// Gets or sets the attribute value type identifier
/// </summary>
public int AttributeValueTypeId { get; set; }
/// <summary>
/// Gets or sets the associated product identifier (used only with AttributeValueType.AssociatedToProduct)
/// </summary>
public int AssociatedProductId { get; set; }
/// <summary>
/// Gets or sets the product attribute name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the color RGB value (used with "Color squares" attribute type)
/// </summary>
public string ColorSquaresRgb { get; set; }
/// <summary>
/// Gets or sets the picture ID for image square (used with "Image squares" attribute type)
/// </summary>
public int ImageSquaresPictureId { get; set; }
/// <summary>
/// Gets or sets the price adjustment (used only with AttributeValueType.Simple)
/// </summary>
public decimal PriceAdjustment { get; set; }
/// <summary>
/// Gets or sets a value indicating whether "price adjustment" is specified as percentage (used only with AttributeValueType.Simple)
/// </summary>
public bool PriceAdjustmentUsePercentage { get; set; }
/// <summary>
/// Gets or sets the weight adjustment (used only with AttributeValueType.Simple)
/// </summary>
public decimal WeightAdjustment { get; set; }
/// <summary>
/// Gets or sets the attribute value cost (used only with AttributeValueType.Simple)
/// </summary>
public decimal Cost { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the customer can enter the quantity of associated product (used only with AttributeValueType.AssociatedToProduct)
/// </summary>
public bool CustomerEntersQty { get; set; }
/// <summary>
/// Gets or sets the quantity of associated product (used only with AttributeValueType.AssociatedToProduct)
/// </summary>
public int Quantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the value is pre-selected
/// </summary>
public bool IsPreSelected { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets the picture (identifier) associated with this value. This picture should replace a product main picture once clicked (selected).
/// </summary>
public int PictureId { get; set; }
/// <summary>
/// Gets or sets the attribute value type
/// </summary>
public AttributeValueType AttributeValueType
{
get => (AttributeValueType)AttributeValueTypeId;
set => AttributeValueTypeId = (int)value;
}
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product category mapping
/// </summary>
public partial class ProductCategory : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the category identifier
/// </summary>
public int CategoryId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is featured
/// </summary>
public bool IsFeaturedProduct { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,310 @@
using Nop.Core.Configuration;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Product editor settings
/// </summary>
public class ProductEditorSettings : ISettings
{
/// <summary>
/// Gets or sets a value indicating whether 'Product type' field is shown
/// </summary>
public bool ProductType { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Visible individually' field is shown
/// </summary>
public bool VisibleIndividually { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Product template' field is shown
/// </summary>
public bool ProductTemplate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Admin comment' field is shown
/// </summary>
public bool AdminComment { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Vendor' field is shown
/// </summary>
public bool Vendor { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Stores' field is shown
/// </summary>
public bool Stores { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'ACL' field is shown
/// </summary>
public bool ACL { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Show on home page' field is shown
/// </summary>
public bool ShowOnHomepage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Allow customer reviews' field is shown
/// </summary>
public bool AllowCustomerReviews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Product tags' field is shown
/// </summary>
public bool ProductTags { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Manufacturer part number' field is shown
/// </summary>
public bool ManufacturerPartNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'GTIN' field is shown
/// </summary>
public bool GTIN { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Product cost' field is shown
/// </summary>
public bool ProductCost { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Tier prices' field is shown
/// </summary>
public bool TierPrices { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Discounts' field is shown
/// </summary>
public bool Discounts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Disable buy button' field is shown
/// </summary>
public bool DisableBuyButton { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Disable wishlist button' field is shown
/// </summary>
public bool DisableWishlistButton { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Available for pre-order' field is shown
/// </summary>
public bool AvailableForPreOrder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Call for price' field is shown
/// </summary>
public bool CallForPrice { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Old price' field is shown
/// </summary>
public bool OldPrice { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Customer enters price' field is shown
/// </summary>
public bool CustomerEntersPrice { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'PAngV' field is shown
/// </summary>
public bool PAngV { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Require other products added to the cart' field is shown
/// </summary>
public bool RequireOtherProductsAddedToCart { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Is gift card' field is shown
/// </summary>
public bool IsGiftCard { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Downloadable product' field is shown
/// </summary>
public bool DownloadableProduct { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Recurring product' field is shown
/// </summary>
public bool RecurringProduct { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Is rental' field is shown
/// </summary>
public bool IsRental { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Free shipping' field is shown
/// </summary>
public bool FreeShipping { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Ship separately' field is shown
/// </summary>
public bool ShipSeparately { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Additional shipping charge' field is shown
/// </summary>
public bool AdditionalShippingCharge { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Delivery date' field is shown
/// </summary>
public bool DeliveryDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Telecommunications, broadcasting and electronic services' field is shown
/// </summary>
public bool TelecommunicationsBroadcastingElectronicServices { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Product availability range' field is shown
/// </summary>
public bool ProductAvailabilityRange { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Use multiple warehouses' field is shown
/// </summary>
public bool UseMultipleWarehouses { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Warehouse' field is shown
/// </summary>
public bool Warehouse { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Display stock availability' field is shown
/// </summary>
public bool DisplayStockAvailability { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Minimum stock quantity' field is shown
/// </summary>
public bool MinimumStockQuantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Low stock activity' field is shown
/// </summary>
public bool LowStockActivity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Notify admin for quantity below' field is shown
/// </summary>
public bool NotifyAdminForQuantityBelow { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Backorders' field is shown
/// </summary>
public bool Backorders { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Allow back in stock subscriptions' field is shown
/// </summary>
public bool AllowBackInStockSubscriptions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Minimum cart quantity' field is shown
/// </summary>
public bool MinimumCartQuantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Maximum cart quantity' field is shown
/// </summary>
public bool MaximumCartQuantity { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Allowed quantities' field is shown
/// </summary>
public bool AllowedQuantities { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Allow only existing attribute combinations' field is shown
/// </summary>
public bool AllowAddingOnlyExistingAttributeCombinations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Not returnable' field is shown
/// </summary>
public bool NotReturnable { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Weight' field is shown
/// </summary>
public bool Weight { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Dimension' fields (height, length, width) are shown
/// </summary>
public bool Dimensions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Available start date' field is shown
/// </summary>
public bool AvailableStartDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Available end date' field is shown
/// </summary>
public bool AvailableEndDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Mark as new' field is shown
/// </summary>
public bool MarkAsNew { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Published' field is shown
/// </summary>
public bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Related products' block is shown
/// </summary>
public bool RelatedProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Cross-sells products' block is shown
/// </summary>
public bool CrossSellsProducts { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'SEO' tab is shown
/// </summary>
public bool Seo { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Purchased with orders' tab is shown
/// </summary>
public bool PurchasedWithOrders { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Product attributes' tab is shown
/// </summary>
public bool ProductAttributes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Specification attributes' tab is shown
/// </summary>
public bool SpecificationAttributes { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Manufacturers' field is shown
/// </summary>
public bool Manufacturers { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 'Stock quantity history' tab is shown
/// </summary>
public bool StockQuantityHistory { get; set; }
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product manufacturer mapping
/// </summary>
public partial class ProductManufacturer : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the manufacturer identifier
/// </summary>
public int ManufacturerId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the product is featured
/// </summary>
public bool IsFeaturedProduct { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product picture mapping
/// </summary>
public partial class ProductPicture : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the picture identifier
/// </summary>
public int PictureId { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product-product tag mapping class
/// </summary>
public partial class ProductProductTagMapping : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the product tag identifier
/// </summary>
public int ProductTagId { get; set; }
}
}
@@ -0,0 +1,70 @@
using System;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product review
/// </summary>
public partial class ProductReview : BaseEntity
{
/// <summary>
/// Gets or sets the customer identifier
/// </summary>
public int CustomerId { get; set; }
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the store identifier
/// </summary>
public int StoreId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the content is approved
/// </summary>
public bool IsApproved { get; set; }
/// <summary>
/// Gets or sets the title
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets or sets the review text
/// </summary>
public string ReviewText { get; set; }
/// <summary>
/// Gets or sets the reply text
/// </summary>
public string ReplyText { get; set; }
/// <summary>
/// Gets or sets the value indicating whether the customer is already notified of the reply to review
/// </summary>
public bool CustomerNotifiedOfReply { get; set; }
/// <summary>
/// Review rating
/// </summary>
public int Rating { get; set; }
/// <summary>
/// Review helpful votes total
/// </summary>
public int HelpfulYesTotal { get; set; }
/// <summary>
/// Review not helpful votes total
/// </summary>
public int HelpfulNoTotal { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product review helpfulness
/// </summary>
public partial class ProductReviewHelpfulness : BaseEntity
{
/// <summary>
/// Gets or sets the product review identifier
/// </summary>
public int ProductReviewId { get; set; }
/// <summary>
/// A value indicating whether a review a helpful
/// </summary>
public bool WasHelpful { get; set; }
/// <summary>
/// Gets or sets the customer identifier
/// </summary>
public int CustomerId { get; set; }
}
}
@@ -0,0 +1,25 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product review and review type mapping
/// </summary>
public partial class ProductReviewReviewTypeMapping : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the product review identifier
/// </summary>
public int ProductReviewId { get; set; }
/// <summary>
/// Gets or sets the review type identifier
/// </summary>
public int ReviewTypeId { get; set; }
/// <summary>
/// Gets or sets the rating
/// </summary>
public int Rating { get; set; }
}
}
@@ -0,0 +1,38 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents the product sorting
/// </summary>
public enum ProductSortingEnum
{
/// <summary>
/// Position (display order)
/// </summary>
Position = 0,
/// <summary>
/// Name: A to Z
/// </summary>
NameAsc = 5,
/// <summary>
/// Name: Z to A
/// </summary>
NameDesc = 6,
/// <summary>
/// Price: Low to High
/// </summary>
PriceAsc = 10,
/// <summary>
/// Price: High to Low
/// </summary>
PriceDesc = 11,
/// <summary>
/// Product creation date
/// </summary>
CreatedOn = 15,
}
}
@@ -0,0 +1,54 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product specification attribute
/// </summary>
public partial class ProductSpecificationAttribute : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the attribute type ID
/// </summary>
public int AttributeTypeId { get; set; }
/// <summary>
/// Gets or sets the specification attribute identifier
/// </summary>
public int SpecificationAttributeOptionId { get; set; }
/// <summary>
/// Gets or sets the custom value
/// </summary>
public string CustomValue { get; set; }
/// <summary>
/// Gets or sets whether the attribute can be filtered by
/// </summary>
public bool AllowFiltering { get; set; }
/// <summary>
/// Gets or sets whether the attribute will be shown on the product page
/// </summary>
public bool ShowOnProductPage { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets the attribute control type
/// </summary>
public SpecificationAttributeType AttributeType
{
get => (SpecificationAttributeType)AttributeTypeId;
set => AttributeTypeId = (int)value;
}
}
}
@@ -0,0 +1,16 @@
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Seo;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product tag
/// </summary>
public partial class ProductTag : BaseEntity, ILocalizedEntity, ISlugSupported
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product template
/// </summary>
public partial class ProductTemplate : BaseEntity
{
/// <summary>
/// Gets or sets the template name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the view path
/// </summary>
public string ViewPath { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets a comma-separated list of product type identifiers NOT supported by this template
/// </summary>
public string IgnoredProductTypes { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a product type
/// </summary>
public enum ProductType
{
/// <summary>
/// Simple
/// </summary>
SimpleProduct = 5,
/// <summary>
/// Grouped (product with variants)
/// </summary>
GroupedProduct = 10,
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a record to manage product inventory per warehouse
/// </summary>
public partial class ProductWarehouseInventory : BaseEntity
{
/// <summary>
/// Gets or sets the product identifier
/// </summary>
public int ProductId { get; set; }
/// <summary>
/// Gets or sets the warehouse identifier
/// </summary>
public int WarehouseId { get; set; }
/// <summary>
/// Gets or sets the stock quantity
/// </summary>
public int StockQuantity { get; set; }
/// <summary>
/// Gets or sets the reserved quantity (ordered but not shipped yet)
/// </summary>
public int ReservedQuantity { get; set; }
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a recurring product cycle period
/// </summary>
public enum RecurringProductCyclePeriod
{
/// <summary>
/// Days
/// </summary>
Days = 0,
/// <summary>
/// Weeks
/// </summary>
Weeks = 10,
/// <summary>
/// Months
/// </summary>
Months = 20,
/// <summary>
/// Years
/// </summary>
Years = 30,
}
}
@@ -0,0 +1,23 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a related product
/// </summary>
public partial class RelatedProduct : BaseEntity
{
/// <summary>
/// Gets or sets the first product identifier
/// </summary>
public int ProductId1 { get; set; }
/// <summary>
/// Gets or sets the second product identifier
/// </summary>
public int ProductId2 { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
}
}
@@ -0,0 +1,28 @@
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a rental product period (for prices)
/// </summary>
public enum RentalPricePeriod
{
/// <summary>
/// Days
/// </summary>
Days = 0,
/// <summary>
/// Weeks
/// </summary>
Weeks = 10,
/// <summary>
/// Months
/// </summary>
Months = 20,
/// <summary>
/// Years
/// </summary>
Years = 30,
}
}
@@ -0,0 +1,35 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a review type
/// </summary>
public partial class ReviewType : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the review type is visible to all customers
/// </summary>
public bool VisibleToAllCustomers { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the review type is required
/// </summary>
public bool IsRequired { get; set; }
}
}
@@ -0,0 +1,25 @@
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.Catalog
{
/// <summary>
/// Represents a specification attribute
/// </summary>
public partial class SpecificationAttribute : BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets the specification attribute group identifier
/// </summary>
public int? SpecificationAttributeGroupId { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More