Merge remote-tracking branch 'origin/feature/data-and-ui-customization-v2' into dev

# Conflicts:
#	docker-compose.override.yml
#	src/Web/WebMVC/WebMVC.csproj
#	src/Web/WebMVC/wwwroot/css/shared/components/identity/identity.css
#	src/Web/WebMVC/wwwroot/css/site.min.css
#	src/Web/WebSPA/AppSettings.cs
This commit is contained in:
Eduard Tomas 2017-06-28 12:20:20 +02:00
commit 96c3f5c2bc
98 changed files with 2479 additions and 602 deletions

View File

@ -29,6 +29,7 @@ services:
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq - EventBusConnection=rabbitmq
- UseCustomizationData=True
ports: ports:
- "5101:80" - "5101:80"
@ -40,6 +41,7 @@ services:
- XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word - ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105. - MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105.
- UseCustomizationData=True
ports: ports:
- "5105:80" - "5105:80"
@ -50,6 +52,7 @@ services:
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq - EventBusConnection=rabbitmq
- UseCustomizationData=True
ports: ports:
- "5102:80" - "5102:80"
@ -79,6 +82,7 @@ services:
- OrderingUrlHC=http://ordering.api/hc - OrderingUrlHC=http://ordering.api/hc
- IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
- BasketUrlHC=http://basket.api/hc - BasketUrlHC=http://basket.api/hc
- UseCustomizationData=True
ports: ports:
- "5104:80" - "5104:80"
@ -92,6 +96,7 @@ services:
- IdentityUrl=http://10.0.75.1:5105 - IdentityUrl=http://10.0.75.1:5105
- MarketingUrl=http://marketing.api #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. - MarketingUrl=http://marketing.api #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser.
#Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. #Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.
- UseCustomizationData=True
ports: ports:
- "5100:80" - "5100:80"

View File

@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.12 VisualStudioVersion = 15.0.26430.12
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3AF739CD-81D8-428D-A08A-0A58372DEBF6}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3AF739CD-81D8-428D-A08A-0A58372DEBF6}"
@ -42,8 +44,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\U
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}"
EndProject EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "test\Services\IntegrationTests\IntegrationTests.csproj", "{5B810E3D-112E-4857-B197-F09D2FD41E27}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "test\Services\IntegrationTests\IntegrationTests.csproj", "{5B810E3D-112E-4857-B197-F09D2FD41E27}"

View File

@ -1,8 +1,20 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.6 VisualStudioVersion = 15.0.26430.13
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
ProjectSection(ProjectDependencies) = postProject
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2} = {9842DB3A-1391-48C7-A49C-2FABD0A18AC2}
{23FB706A-2701-41E9-8BF9-28936001CA41} = {23FB706A-2701-41E9-8BF9-28936001CA41}
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {F0333D8E-0B27-42B7-B2C6-78F3657624E2}
{42681D9D-750A-4DF7-BD9F-9292CFD5C253} = {42681D9D-750A-4DF7-BD9F-9292CFD5C253}
{2110CBB0-3B38-4EE4-A743-DF6968D80D90} = {2110CBB0-3B38-4EE4-A743-DF6968D80D90}
{231226CE-690B-4979-8870-9A79D80928E2} = {231226CE-690B-4979-8870-9A79D80928E2}
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357} = {2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{91CF7717-08AB-4E65-B10E-0B426F01E2E8}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{91CF7717-08AB-4E65-B10E-0B426F01E2E8}"
@ -49,7 +61,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.UnitTests
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.Droid", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.Droid\eShopOnContainers.TestRunner.Droid.csproj", "{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.Droid", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.Droid\eShopOnContainers.TestRunner.Droid.csproj", "{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.Windows", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.Windows\eShopOnContainers.TestRunner.Windows.csproj", "{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.Windows", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.Windows\eShopOnContainers.TestRunner.Windows.csproj", "{A7337243-33B8-463A-87AD-944B75EFD820}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.iOS", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.iOS\eShopOnContainers.TestRunner.iOS.csproj", "{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.TestRunner.iOS", "src\Mobile\eShopOnContainers\eShopOnContainers.TestRunner.iOS\eShopOnContainers.TestRunner.iOS.csproj", "{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}"
EndProject EndProject
@ -67,18 +79,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\U
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}"
EndProject EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
ProjectSection(ProjectDependencies) = postProject
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2} = {9842DB3A-1391-48C7-A49C-2FABD0A18AC2}
{23FB706A-2701-41E9-8BF9-28936001CA41} = {23FB706A-2701-41E9-8BF9-28936001CA41}
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {F0333D8E-0B27-42B7-B2C6-78F3657624E2}
{42681D9D-750A-4DF7-BD9F-9292CFD5C253} = {42681D9D-750A-4DF7-BD9F-9292CFD5C253}
{2110CBB0-3B38-4EE4-A743-DF6968D80D90} = {2110CBB0-3B38-4EE4-A743-DF6968D80D90}
{231226CE-690B-4979-8870-9A79D80928E2} = {231226CE-690B-4979-8870-9A79D80928E2}
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357} = {2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{B473B70F-0796-4862-B1AD-BB742D93B868}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{B473B70F-0796-4862-B1AD-BB742D93B868}"
@ -133,6 +133,54 @@ Global
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|Any CPU.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|ARM.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|ARM.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhone.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhone.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.Build.0 = Release|Any CPU
{2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU {2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {2110CBB0-3B38-4EE4-A743-DF6968D80D90}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@ -599,72 +647,72 @@ Global
{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.ActiveCfg = Release|Any CPU {A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.ActiveCfg = Release|Any CPU
{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.Build.0 = Release|Any CPU {A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.Build.0 = Release|Any CPU
{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.Deploy.0 = Release|Any CPU {A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1}.Release|x86.Deploy.0 = Release|Any CPU
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|Any CPU.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|Any CPU.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|Any CPU.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|Any CPU.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|Any CPU.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|Any CPU.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|ARM.ActiveCfg = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|ARM.ActiveCfg = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|ARM.Build.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|ARM.Build.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|ARM.Deploy.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|ARM.Deploy.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhone.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhone.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhone.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhone.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhone.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhone.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x64.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x64.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x64.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x64.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x64.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x64.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x86.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x86.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x86.Build.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x86.Build.0 = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Ad-Hoc|x86.Deploy.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Ad-Hoc|x86.Deploy.0 = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|Any CPU.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|Any CPU.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|Any CPU.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|Any CPU.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|Any CPU.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|Any CPU.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|ARM.ActiveCfg = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|ARM.ActiveCfg = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|ARM.Build.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|ARM.Build.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|ARM.Deploy.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|ARM.Deploy.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhone.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhone.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhone.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhone.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhone.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhone.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhoneSimulator.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhoneSimulator.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhoneSimulator.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhoneSimulator.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|iPhoneSimulator.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|iPhoneSimulator.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x64.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x64.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x64.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x64.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x64.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x64.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x86.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x86.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x86.Build.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x86.Build.0 = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.AppStore|x86.Deploy.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.AppStore|x86.Deploy.0 = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|Any CPU.ActiveCfg = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|Any CPU.ActiveCfg = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|Any CPU.Build.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|Any CPU.Build.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|Any CPU.Deploy.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|Any CPU.Deploy.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|ARM.ActiveCfg = Debug|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|ARM.ActiveCfg = Debug|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|ARM.Build.0 = Debug|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|ARM.Build.0 = Debug|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|ARM.Deploy.0 = Debug|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|ARM.Deploy.0 = Debug|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhone.ActiveCfg = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhone.ActiveCfg = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhone.Build.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhone.Build.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhone.Deploy.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhone.Deploy.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhoneSimulator.Build.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhoneSimulator.Build.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|iPhoneSimulator.Deploy.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|iPhoneSimulator.Deploy.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x64.ActiveCfg = Debug|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x64.ActiveCfg = Debug|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x64.Build.0 = Debug|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x64.Build.0 = Debug|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x64.Deploy.0 = Debug|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x64.Deploy.0 = Debug|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x86.ActiveCfg = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x86.ActiveCfg = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x86.Build.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x86.Build.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Debug|x86.Deploy.0 = Debug|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Debug|x86.Deploy.0 = Debug|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|Any CPU.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|Any CPU.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|ARM.ActiveCfg = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Release|ARM.ActiveCfg = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|ARM.Build.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Release|ARM.Build.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|ARM.Deploy.0 = Release|ARM {A7337243-33B8-463A-87AD-944B75EFD820}.Release|ARM.Deploy.0 = Release|ARM
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|iPhone.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|iPhone.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|iPhoneSimulator.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|iPhoneSimulator.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x64.ActiveCfg = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x64.ActiveCfg = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x64.Build.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x64.Build.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x64.Deploy.0 = Release|x64 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x64.Deploy.0 = Release|x64
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x86.ActiveCfg = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.ActiveCfg = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x86.Build.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.Build.0 = Release|x86
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F}.Release|x86.Deploy.0 = Release|x86 {A7337243-33B8-463A-87AD-944B75EFD820}.Release|x86.Deploy.0 = Release|x86
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
@ -986,54 +1034,6 @@ Global
{A579E108-5445-403D-A407-339AC4D1611B}.Release|x64.Build.0 = Release|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Release|x64.Build.0 = Release|Any CPU
{A579E108-5445-403D-A407-339AC4D1611B}.Release|x86.ActiveCfg = Release|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Release|x86.ActiveCfg = Release|Any CPU
{A579E108-5445-403D-A407-339AC4D1611B}.Release|x86.Build.0 = Release|Any CPU {A579E108-5445-403D-A407-339AC4D1611B}.Release|x86.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.AppStore|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|ARM.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhone.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x64.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x64.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Debug|x86.Build.0 = Debug|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|Any CPU.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|ARM.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|ARM.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhone.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhone.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.Build.0 = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.ActiveCfg = Release|Any CPU
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.Build.0 = Release|Any CPU
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU {3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
@ -1492,7 +1492,7 @@ Global
{B7B1D395-4E06-4036-BE86-C216756B9367} = {A857AD10-40FF-4303-BEC2-FF1C58D5735E} {B7B1D395-4E06-4036-BE86-C216756B9367} = {A857AD10-40FF-4303-BEC2-FF1C58D5735E}
{F7B6A162-BC4D-4924-B16A-713F9B0344E7} = {B7B1D395-4E06-4036-BE86-C216756B9367} {F7B6A162-BC4D-4924-B16A-713F9B0344E7} = {B7B1D395-4E06-4036-BE86-C216756B9367}
{A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1} = {B7B1D395-4E06-4036-BE86-C216756B9367} {A289A7F0-ACD8-42AE-87B6-AB1AFD310BF1} = {B7B1D395-4E06-4036-BE86-C216756B9367}
{02680C26-CA1D-4D9D-A7E3-D66AF5BE6F2F} = {B7B1D395-4E06-4036-BE86-C216756B9367} {A7337243-33B8-463A-87AD-944B75EFD820} = {B7B1D395-4E06-4036-BE86-C216756B9367}
{B68C2B56-7581-46AE-B55D-D25DDFD3BFE3} = {B7B1D395-4E06-4036-BE86-C216756B9367} {B68C2B56-7581-46AE-B55D-D25DDFD3BFE3} = {B7B1D395-4E06-4036-BE86-C216756B9367}
{95F1F07C-4D92-4742-BD07-E5B805AAB651} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B} {95F1F07C-4D92-4742-BD07-E5B805AAB651} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
{02DF7FEE-C302-433D-A6CD-237A2569F236} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {02DF7FEE-C302-433D-A6CD-237A2569F236} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}

View File

@ -21,6 +21,11 @@
<Content Include="Pics\**\*;"> <Content Include="Pics\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Remove="Setup\Catalogitems - Copy.zip" />
<None Remove="Setup\Catalogitems - Copy.zip" />
<Compile Include="IntegrationEvents\EventHandling\AnyFutureIntegrationEventHandler.cs.txt" /> <Compile Include="IntegrationEvents\EventHandling\AnyFutureIntegrationEventHandler.cs.txt" />
<Content Update="web.config;"> <Content Update="web.config;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
@ -50,6 +55,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -72,6 +78,9 @@
<None Update="Pics\*"> <None Update="Pics\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,5 +5,7 @@
public string ExternalCatalogBaseUrl {get;set;} public string ExternalCatalogBaseUrl {get;set;}
public string EventBusConnection { get; set; } public string EventBusConnection { get; set; }
public bool UseCustomizationData { get; set; }
} }
} }

View File

@ -235,7 +235,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
items.ForEach(x => items.ForEach(x =>
{ {
x.PictureUri = x.PictureUri.Replace("http://externalcatalogbaseurltobereplaced", baseUri); if (!x.PictureUri.Contains('/'))
{
x.PictureUri = $"{baseUri}/api/v1/pic/{x.PictureUri}";
}
}); });
return items; return items;

View File

@ -15,16 +15,58 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
_env = env; _env = env;
} }
[HttpGet("{id}")] [HttpGet("{filename}")]
// GET: /<controller>/ // GET: /<controller>/
public IActionResult GetImage(int id) public IActionResult GetImage(string filename)
{ {
var webRoot = _env.WebRootPath; var webRoot = _env.WebRootPath;
var path = Path.Combine(webRoot, id + ".png"); var path = Path.Combine(webRoot, filename);
var buffer = System.IO.File.ReadAllBytes(path); string imageFileExtension = Path.GetExtension(filename);
string mimetype = GetImageMimeTypeFromImageFileExtension(imageFileExtension);
return File(buffer, "image/png");
var buffer = System.IO.File.ReadAllBytes(path);
return File(buffer, mimetype);
}
private string GetImageMimeTypeFromImageFileExtension(string extension)
{
string mimetype;
switch (extension)
{
case "png":
mimetype = "image/png";
break;
case "gif":
mimetype = "image/gif";
break;
case "jpg":
case "jpeg":
mimetype = "image/jpeg";
break;
case "bmp":
mimetype = "image/bmp";
break;
case "tiff":
mimetype = "image/tiff";
break;
case "wmf":
mimetype = "image/wmf";
break;
case "jp2":
mimetype = "image/jp2";
break;
case "svg":
mimetype = "image/svg+xml";
break;
default:
mimetype = "application/octet-stream";
break;
}
return mimetype;
} }
} }
} }

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Catalog.API.Extensions
{
public static class LinqSelectExtensions
{
public static IEnumerable<SelectTryResult<TSource, TResult>> SelectTry<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
{
foreach (TSource element in enumerable)
{
SelectTryResult<TSource, TResult> returnedValue;
try
{
returnedValue = new SelectTryResult<TSource, TResult>(element, selector(element), null);
}
catch (Exception ex)
{
returnedValue = new SelectTryResult<TSource, TResult>(element, default(TResult), ex);
}
yield return returnedValue;
}
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.CaughtException));
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<TSource, Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.Source, x.CaughtException));
}
public class SelectTryResult<TSource, TResult>
{
internal SelectTryResult(TSource source, TResult result, Exception exception)
{
Source = source;
Result = result;
CaughtException = exception;
}
public TSource Source { get; private set; }
public TResult Result { get; private set; }
public Exception CaughtException { get; private set; }
}
}
}

View File

@ -2,47 +2,115 @@
{ {
using EntityFrameworkCore; using EntityFrameworkCore;
using Extensions.Logging; using Extensions.Logging;
using global::Catalog.API.Extensions;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Model; using Model;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
public class CatalogContextSeed public class CatalogContextSeed
{ {
public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, int? retry = 0) public static async Task SeedAsync(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory, int? retry = 0)
{ {
var log = loggerFactory.CreateLogger("catalog seed");
var context = (CatalogContext)applicationBuilder var context = (CatalogContext)applicationBuilder
.ApplicationServices.GetService(typeof(CatalogContext)); .ApplicationServices.GetService(typeof(CatalogContext));
context.Database.Migrate(); context.Database.Migrate();
var settings = (CatalogSettings)applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<CatalogSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
var picturePath = env.WebRootPath;
if (!context.CatalogBrands.Any()) if (!context.CatalogBrands.Any())
{ {
context.CatalogBrands.AddRange( context.CatalogBrands.AddRange(useCustomizationData
GetPreconfiguredCatalogBrands()); ? GetCatalogBrandsFromFile(contentRootPath, log)
: GetPreconfiguredCatalogBrands()
);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
if (!context.CatalogTypes.Any()) if (!context.CatalogTypes.Any())
{ {
context.CatalogTypes.AddRange( context.CatalogTypes.AddRange(useCustomizationData
GetPreconfiguredCatalogTypes()); ? GetCatalogTypesFromFile(contentRootPath, log)
: GetPreconfiguredCatalogTypes()
);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
if (!context.CatalogItems.Any()) if (!context.CatalogItems.Any())
{ {
context.CatalogItems.AddRange( context.CatalogItems.AddRange(useCustomizationData
GetPreconfiguredItems()); ? GetCatalogItemsFromFile(contentRootPath, context, log)
: GetPreconfiguredItems()
);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
GetCatalogItemPictures(contentRootPath, picturePath);
} }
} }
static IEnumerable<CatalogBrand> GetCatalogBrandsFromFile(string contentRootPath, ILogger log)
{
string csvFileCatalogBrands = Path.Combine(contentRootPath, "Setup", "CatalogBrands.csv");
if (!File.Exists(csvFileCatalogBrands))
{
return GetPreconfiguredCatalogBrands();
}
string[] csvheaders;
try
{
string[] requiredHeaders = { "catalogbrand" };
csvheaders = GetHeaders( csvFileCatalogBrands, requiredHeaders );
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetPreconfiguredCatalogBrands();
}
return File.ReadAllLines(csvFileCatalogBrands)
.Skip(1) // skip header row
.SelectTry(x => CreateCatalogBrand(x))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null);
}
static CatalogBrand CreateCatalogBrand(string brand)
{
brand = brand.Trim('"').Trim();
if (String.IsNullOrEmpty(brand))
{
throw new Exception("catalog Brand Name is empty");
}
return new CatalogBrand
{
Brand = brand,
};
}
static IEnumerable<CatalogBrand> GetPreconfiguredCatalogBrands() static IEnumerable<CatalogBrand> GetPreconfiguredCatalogBrands()
{ {
return new List<CatalogBrand>() return new List<CatalogBrand>()
@ -50,11 +118,54 @@
new CatalogBrand() { Brand = "Azure"}, new CatalogBrand() { Brand = "Azure"},
new CatalogBrand() { Brand = ".NET" }, new CatalogBrand() { Brand = ".NET" },
new CatalogBrand() { Brand = "Visual Studio" }, new CatalogBrand() { Brand = "Visual Studio" },
new CatalogBrand() { Brand = "SQL Server" }, new CatalogBrand() { Brand = "SQL Server" },
new CatalogBrand() { Brand = "Other" } new CatalogBrand() { Brand = "Other" }
}; };
} }
static IEnumerable<CatalogType> GetCatalogTypesFromFile(string contentRootPath, ILogger log)
{
string csvFileCatalogTypes = Path.Combine(contentRootPath, "Setup", "CatalogTypes.csv");
if (!File.Exists(csvFileCatalogTypes))
{
return GetPreconfiguredCatalogTypes();
}
string[] csvheaders;
try
{
string[] requiredHeaders = { "catalogtype" };
csvheaders = GetHeaders( csvFileCatalogTypes, requiredHeaders );
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetPreconfiguredCatalogTypes();
}
return File.ReadAllLines(csvFileCatalogTypes)
.Skip(1) // skip header row
.SelectTry(x => CreateCatalogType(x))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null);
}
static CatalogType CreateCatalogType(string type)
{
type = type.Trim('"').Trim();
if (String.IsNullOrEmpty(type))
{
throw new Exception("catalog Type Name is empty");
}
return new CatalogType
{
Type = type,
};
}
static IEnumerable<CatalogType> GetPreconfiguredCatalogTypes() static IEnumerable<CatalogType> GetPreconfiguredCatalogTypes()
{ {
return new List<CatalogType>() return new List<CatalogType>()
@ -66,23 +177,204 @@
}; };
} }
static IEnumerable<CatalogItem> GetCatalogItemsFromFile(string contentRootPath, CatalogContext context, ILogger log)
{
string csvFileCatalogItems = Path.Combine(contentRootPath, "Setup", "CatalogItems.csv");
if (!File.Exists(csvFileCatalogItems))
{
return GetPreconfiguredItems();
}
string[] csvheaders;
try
{
string[] requiredHeaders = { "catalogtypename", "catalogbrandname", "description", "name", "price", "pictureuri" };
string[] optionalheaders = { "availablestock", "restockthreshold", "maxstockthreshold", "onreorder" };
csvheaders = GetHeaders(csvFileCatalogItems, requiredHeaders, optionalheaders );
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetPreconfiguredItems();
}
var catalogTypeIdLookup = context.CatalogTypes.ToDictionary(ct => ct.Type, ct => ct.Id);
var catalogBrandIdLookup = context.CatalogBrands.ToDictionary(ct => ct.Brand, ct => ct.Id);
return File.ReadAllLines(csvFileCatalogItems)
.Skip(1) // skip header row
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
.SelectTry(column => CreateCatalogItem(column, csvheaders, catalogTypeIdLookup, catalogBrandIdLookup))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null);
}
static CatalogItem CreateCatalogItem(string[] column, string[] headers, Dictionary<String, int> catalogTypeIdLookup, Dictionary<String, int> catalogBrandIdLookup)
{
if (column.Count() != headers.Count())
{
throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'");
}
string catalogTypeName = column[Array.IndexOf(headers, "catalogtypename")].Trim('"').Trim();
if (!catalogTypeIdLookup.ContainsKey(catalogTypeName))
{
throw new Exception($"type={catalogTypeName} does not exist in catalogTypes");
}
string catalogBrandName = column[Array.IndexOf(headers, "catalogbrandname")].Trim('"').Trim();
if (!catalogBrandIdLookup.ContainsKey(catalogBrandName))
{
throw new Exception($"type={catalogTypeName} does not exist in catalogTypes");
}
string priceString = column[Array.IndexOf(headers, "price")].Trim('"').Trim();
if (!Decimal.TryParse(priceString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out Decimal price))
{
throw new Exception($"price={priceString}is not a valid decimal number");
}
var catalogItem = new CatalogItem()
{
CatalogTypeId = catalogTypeIdLookup[catalogTypeName],
CatalogBrandId = catalogBrandIdLookup[catalogBrandName],
Description = column[Array.IndexOf(headers, "description")].Trim('"').Trim(),
Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(),
Price = price,
PictureUri = column[Array.IndexOf(headers, "pictureuri")].Trim('"').Trim(),
};
int availableStockIndex = Array.IndexOf(headers, "availablestock");
if (availableStockIndex != -1)
{
string availableStockString = column[availableStockIndex].Trim('"').Trim();
if (!String.IsNullOrEmpty(availableStockString))
{
if ( int.TryParse(availableStockString, out int availableStock))
{
catalogItem.AvailableStock = availableStock;
}
else
{
throw new Exception($"availableStock={availableStockString} is not a valid integer");
}
}
}
int restockThresholdIndex = Array.IndexOf(headers, "restockthreshold");
if (restockThresholdIndex != -1)
{
string restockThresholdString = column[restockThresholdIndex].Trim('"').Trim();
if (!String.IsNullOrEmpty(restockThresholdString))
{
if (int.TryParse(restockThresholdString, out int restockThreshold))
{
catalogItem.RestockThreshold = restockThreshold;
}
else
{
throw new Exception($"restockThreshold={restockThreshold} is not a valid integer");
}
}
}
int maxStockThresholdIndex = Array.IndexOf(headers, "maxstockthreshold");
if (maxStockThresholdIndex != -1)
{
string maxStockThresholdString = column[maxStockThresholdIndex].Trim('"').Trim();
if (!String.IsNullOrEmpty(maxStockThresholdString))
{
if (int.TryParse(maxStockThresholdString, out int maxStockThreshold))
{
catalogItem.MaxStockThreshold = maxStockThreshold;
}
else
{
throw new Exception($"maxStockThreshold={maxStockThreshold} is not a valid integer");
}
}
}
int onReorderIndex = Array.IndexOf(headers, "onreorder");
if (onReorderIndex != -1)
{
string onReorderString = column[onReorderIndex].Trim('"').Trim();
if (!String.IsNullOrEmpty(onReorderString))
{
if (bool.TryParse(onReorderString, out bool onReorder))
{
catalogItem.OnReorder = onReorder;
}
else
{
throw new Exception($"onReorder={onReorderString} is not a valid boolean");
}
}
}
return catalogItem;
}
static IEnumerable<CatalogItem> GetPreconfiguredItems() static IEnumerable<CatalogItem> GetPreconfiguredItems()
{ {
return new List<CatalogItem>() return new List<CatalogItem>()
{ {
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Bot Black Hoodie", Name = ".NET Bot Black Hoodie", Price = 19.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/1", AvailableStock = 100}, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Bot Black Hoodie", Name = ".NET Bot Black Hoodie", Price = 19.5M, PictureUri = "1.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/2", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "2.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/3", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "3.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Foundation T-shirt", Name = ".NET Foundation T-shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/4", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Foundation T-shirt", Name = ".NET Foundation T-shirt", Price = 12, PictureUri = "4.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=5, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/5", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=3,CatalogBrandId=5, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "5.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Blue Hoodie", Name = ".NET Blue Hoodie", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/6", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Blue Hoodie", Name = ".NET Blue Hoodie", Price = 12, PictureUri = "6.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/7", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "7.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Kudu Purple Hoodie", Name = "Kudu Purple Hoodie", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/8", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Kudu Purple Hoodie", Name = "Kudu Purple Hoodie", Price = 8.5M, PictureUri = "8.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=5, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/9", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=1,CatalogBrandId=5, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureUri = "9.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/10", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "10.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/11", AvailableStock = 100 }, new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureUri = "11.png", AvailableStock = 100 },
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/12", AvailableStock = 100 } new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureUri = "12.png", AvailableStock = 100 }
}; };
} }
static string[] GetHeaders(string csvfile, string[] requiredHeaders, string[] optionalHeaders = null)
{
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
if (csvheaders.Count() < requiredHeaders.Count())
{
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is bigger then csv header count '{csvheaders.Count()}' ");
}
if (optionalHeaders != null)
{
if (csvheaders.Count() > (requiredHeaders.Count() + optionalHeaders.Count()))
{
throw new Exception($"csv header count '{csvheaders.Count()}' is larger then required '{requiredHeaders.Count()}' and optional '{optionalHeaders.Count()}' headers count");
}
}
foreach (var requiredHeader in requiredHeaders)
{
if (!csvheaders.Contains(requiredHeader))
{
throw new Exception($"does not contain required header '{requiredHeader}'");
}
}
return csvheaders;
}
static void GetCatalogItemPictures(string contentRootPath, string picturePath)
{
DirectoryInfo directory = new DirectoryInfo(picturePath);
foreach (FileInfo file in directory.GetFiles())
{
file.Delete();
}
string zipFileCatalogItemPictures = Path.Combine(contentRootPath, "Setup", "CatalogItems.zip");
ZipFile.ExtractToDirectory(zipFileCatalogItemPictures, picturePath);
}
} }
} }

View File

@ -0,0 +1,8 @@
CatalogBrand
Azure
.NET
Visual Studio
SQL Server
Other
CatalogBrandTestOne
CatalogBrandTestTwo
1 CatalogBrand
2 Azure
3 .NET
4 Visual Studio
5 SQL Server
6 Other
7 CatalogBrandTestOne
8 CatalogBrandTestTwo

View File

@ -0,0 +1,14 @@
CatalogTypeName,CatalogBrandName,Description,Name,Price,PictureUri,availablestock,onreorder
T-Shirt,.NET,".NET Bot Black Hoodie, and more",.NET Bot Black Hoodie,19.5,1.png,100,false
Mug,.NET,.NET Black & White Mug,.NET Black & White Mug,8.50,2.png,89,true
T-Shirt,Other,Prism White T-Shirt,Prism White T-Shirt,12,3.png,56,false
T-Shirt,.NET,.NET Foundation T-shirt,.NET Foundation T-shirt,12,4.png,120,false
Sheet,Other,Roslyn Red Sheet,Roslyn Red Sheet,8.5,5.png,55,false
T-Shirt,.NET,.NET Blue Hoodie,.NET Blue Hoodie,12,6.png,17,false
T-Shirt,Other,Roslyn Red T-Shirt,Roslyn Red T-Shirt",12,7.png,8,false
T-Shirt,Other,Kudu Purple Hoodie,Kudu Purple Hoodie,8.5,8.png,34,false
Mug,Other,Cup<T> White Mug,Cup<T> White Mug,12,9.png,76,false
Sheet,.NET,.NET Foundation Sheet,.NET Foundation Sheet,12,10.png,11,false
Sheet,.NET,Cup<T> Sheet,Cup<T> Sheet,8.5,11.png,3,false
T-Shirt,Other,Prism White TShirt,Prism White TShirt,12,12.png,0,false
Mug, Other, De los Palotes, pepito, 12, 12.png, 0, false
Can't render this file because it contains an unexpected character in line 8 and column 52.

View File

@ -0,0 +1,7 @@
CatalogType
Mug
T-Shirt
Sheet
USB Memory Stick
CatalogTypeTestOne
CatalogTypeTestTwo
1 CatalogType
2 Mug
3 T-Shirt
4 Sheet
5 USB Memory Stick
6 CatalogTypeTestOne
7 CatalogTypeTestTwo

View File

@ -153,7 +153,7 @@
var context = (CatalogContext)app var context = (CatalogContext)app
.ApplicationServices.GetService(typeof(CatalogContext)); .ApplicationServices.GetService(typeof(CatalogContext));
WaitForSqlAvailabilityAsync(context, loggerFactory, app).Wait(); WaitForSqlAvailabilityAsync(context, loggerFactory, app, env).Wait();
ConfigureEventBus(app); ConfigureEventBus(app);
@ -165,13 +165,13 @@
integrationEventLogContext.Database.Migrate(); integrationEventLogContext.Database.Migrate();
} }
private async Task WaitForSqlAvailabilityAsync(CatalogContext ctx, ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0) private async Task WaitForSqlAvailabilityAsync(CatalogContext ctx, ILoggerFactory loggerFactory, IApplicationBuilder app, IHostingEnvironment env, int retries = 0)
{ {
var logger = loggerFactory.CreateLogger(nameof(Startup)); var logger = loggerFactory.CreateLogger(nameof(Startup));
var policy = CreatePolicy(retries, logger, nameof (WaitForSqlAvailabilityAsync)); var policy = CreatePolicy(retries, logger, nameof (WaitForSqlAvailabilityAsync));
await policy.ExecuteAsync(async () => await policy.ExecuteAsync(async () =>
{ {
await CatalogContextSeed.SeedAsync(app, loggerFactory); await CatalogContextSeed.SeedAsync(app, env, loggerFactory);
}); });
} }

View File

@ -1,6 +1,7 @@
{ {
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word",
"ExternalCatalogBaseUrl": "http://localhost:5101", "ExternalCatalogBaseUrl": "http://localhost:5101",
"UseCustomizationData": true,
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {

View File

@ -8,5 +8,6 @@ namespace eShopOnContainers.Identity
public class AppSettings public class AppSettings
{ {
public string MvcClient { get; set; } public string MvcClient { get; set; }
public bool UseCustomizationData { get; set; }
} }
} }

View File

@ -3,13 +3,21 @@
using AspNetCore.Identity; using AspNetCore.Identity;
using EntityFrameworkCore; using EntityFrameworkCore;
using Extensions.Logging; using Extensions.Logging;
using global::eShopOnContainers.Identity;
using global::Identity.API.Data; using global::Identity.API.Data;
using global::Identity.API.Models; using global::Identity.API.Models;
using Identity.API.Extensions;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
public class ApplicationContextSeed public class ApplicationContextSeed
@ -21,23 +29,38 @@
_passwordHasher = passwordHasher; _passwordHasher = passwordHasher;
} }
public async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, int? retry = 0) public async Task SeedAsync(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory, int? retry = 0)
{ {
int retryForAvaiability = retry.Value; int retryForAvaiability = retry.Value;
try try
{ {
var log = loggerFactory.CreateLogger("application seed");
var context = (ApplicationDbContext)applicationBuilder var context = (ApplicationDbContext)applicationBuilder
.ApplicationServices.GetService(typeof(ApplicationDbContext)); .ApplicationServices.GetService(typeof(ApplicationDbContext));
context.Database.Migrate(); context.Database.Migrate();
var settings = (AppSettings)applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
var webroot = env.WebRootPath;
if (!context.Users.Any()) if (!context.Users.Any())
{ {
context.Users.AddRange( context.Users.AddRange(useCustomizationData
GetDefaultUser()); ? GetUsersFromFile(contentRootPath, log)
: GetDefaultUser());
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
if (useCustomizationData)
{
GetPreconfiguredImages(contentRootPath, webroot, log);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -46,14 +69,93 @@
retryForAvaiability++; retryForAvaiability++;
var log = loggerFactory.CreateLogger("catalog seed"); var log = loggerFactory.CreateLogger("catalog seed");
log.LogError(ex.Message); log.LogError(ex.Message);
await SeedAsync(applicationBuilder, loggerFactory, retryForAvaiability); await SeedAsync(applicationBuilder, env, loggerFactory, retryForAvaiability);
} }
} }
} }
private ApplicationUser GetDefaultUser() private IEnumerable<ApplicationUser> GetUsersFromFile(string contentRootPath, ILogger log)
{ {
var user = string csvFileUsers = Path.Combine(contentRootPath, "Setup", "Users.csv");
if (!File.Exists(csvFileUsers))
{
return GetDefaultUser();
}
string[] csvheaders;
try
{
string[] requiredHeaders = {
"cardholdername", "cardnumber", "cardtype", "city", "country",
"email", "expiration", "lastname", "name", "phonenumber",
"username", "zipcode", "state", "street", "securitynumber",
"normalizedemail", "normalizedusername", "password"
};
csvheaders = GetHeaders(requiredHeaders, csvFileUsers);
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetDefaultUser();
}
List<ApplicationUser> users = File.ReadAllLines(csvFileUsers)
.Skip(1) // skip header column
.Select(row => Regex.Split(row, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)") )
.SelectTry(column => CreateApplicationUser(column, csvheaders))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null)
.ToList();
return users;
}
private ApplicationUser CreateApplicationUser(string[] column, string[] headers)
{
if (column.Count() != headers.Count())
{
throw new Exception($"column count '{column.Count()}' not the same as headers count'{headers.Count()}'");
}
string cardtypeString = column[Array.IndexOf(headers, "cardtype")].Trim('"').Trim();
if (!int.TryParse(cardtypeString, out int cardtype))
{
throw new Exception($"cardtype='{cardtypeString}' is not a number");
}
var user = new ApplicationUser
{
CardHolderName = column[Array.IndexOf(headers, "cardholdername")].Trim('"').Trim(),
CardNumber = column[Array.IndexOf(headers, "cardnumber")].Trim('"').Trim(),
CardType = cardtype,
City = column[Array.IndexOf(headers, "city")].Trim('"').Trim(),
Country = column[Array.IndexOf(headers, "country")].Trim('"').Trim(),
Email = column[Array.IndexOf(headers, "email")].Trim('"').Trim(),
Expiration = column[Array.IndexOf(headers, "expiration")].Trim('"').Trim(),
Id = Guid.NewGuid().ToString(),
LastName = column[Array.IndexOf(headers, "lastname")].Trim('"').Trim(),
Name = column[Array.IndexOf(headers, "name")].Trim('"').Trim(),
PhoneNumber = column[Array.IndexOf(headers, "phonenumber")].Trim('"').Trim(),
UserName = column[Array.IndexOf(headers, "username")].Trim('"').Trim(),
ZipCode = column[Array.IndexOf(headers, "zipcode")].Trim('"').Trim(),
State = column[Array.IndexOf(headers, "state")].Trim('"').Trim(),
Street = column[Array.IndexOf(headers, "street")].Trim('"').Trim(),
SecurityNumber = column[Array.IndexOf(headers, "securitynumber")].Trim('"').Trim(),
NormalizedEmail = column[Array.IndexOf(headers, "normalizedemail")].Trim('"').Trim(),
NormalizedUserName = column[Array.IndexOf(headers, "normalizedusername")].Trim('"').Trim(),
SecurityStamp = Guid.NewGuid().ToString("D"),
PasswordHash = column[Array.IndexOf(headers, "password")].Trim('"').Trim(), // Note: This is the password
};
user.PasswordHash = _passwordHasher.HashPassword(user, user.PasswordHash);
return user;
}
private IEnumerable<ApplicationUser> GetDefaultUser()
{
var user =
new ApplicationUser() new ApplicationUser()
{ {
CardHolderName = "DemoUser", CardHolderName = "DemoUser",
@ -63,23 +165,86 @@
Country = "U.S.", Country = "U.S.",
Email = "demouser@microsoft.com", Email = "demouser@microsoft.com",
Expiration = "12/20", Expiration = "12/20",
Id = Guid.NewGuid().ToString(), Id = Guid.NewGuid().ToString(),
LastName = "DemoLastName", LastName = "DemoLastName",
Name = "DemoUser", Name = "DemoUser",
PhoneNumber = "1234567890", PhoneNumber = "1234567890",
UserName = "demouser@microsoft.com", UserName = "demouser@microsoft.com",
ZipCode = "98052", ZipCode = "98052",
State = "WA", State = "WA",
Street = "15703 NE 61st Ct", Street = "15703 NE 61st Ct",
SecurityNumber = "535", SecurityNumber = "535",
NormalizedEmail = "DEMOUSER@MICROSOFT.COM", NormalizedEmail = "DEMOUSER@MICROSOFT.COM",
NormalizedUserName = "DEMOUSER@MICROSOFT.COM", NormalizedUserName = "DEMOUSER@MICROSOFT.COM",
SecurityStamp = Guid.NewGuid().ToString("D") SecurityStamp = Guid.NewGuid().ToString("D"),
}; };
user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1"); user.PasswordHash = _passwordHasher.HashPassword(user, "Pass@word1");
return user; return new List<ApplicationUser>()
{
user
};
}
static string[] GetHeaders(string[] requiredHeaders, string csvfile)
{
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
if (csvheaders.Count() != requiredHeaders.Count())
{
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'");
}
foreach (var requiredHeader in requiredHeaders)
{
if (!csvheaders.Contains(requiredHeader))
{
throw new Exception($"does not contain required header '{requiredHeader}'");
}
}
return csvheaders;
}
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger log)
{
try
{
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
log.LogError($" zip file '{imagesZipFile}' does not exists.");
return;
}
string imagePath = Path.Combine(webroot, "images");
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in zip.Entries)
{
if (imageFiles.Contains(entry.Name))
{
string destinationFilename = Path.Combine(imagePath, entry.Name);
if (File.Exists(destinationFilename))
{
File.Delete(destinationFilename);
}
entry.ExtractToFile(destinationFilename);
}
else
{
log.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
}
}
}
}
catch (Exception ex)
{
log.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
}
} }
} }
} }

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Identity.API.Extensions
{
public static class LinqSelectExtensions
{
public static IEnumerable<SelectTryResult<TSource, TResult>> SelectTry<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
{
foreach (TSource element in enumerable)
{
SelectTryResult<TSource, TResult> returnedValue;
try
{
returnedValue = new SelectTryResult<TSource, TResult>(element, selector(element), null);
}
catch (Exception ex)
{
returnedValue = new SelectTryResult<TSource, TResult>(element, default(TResult), ex);
}
yield return returnedValue;
}
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.CaughtException));
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<TSource, Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.Source, x.CaughtException));
}
public class SelectTryResult<TSource, TResult>
{
internal SelectTryResult(TSource source, TResult result, Exception exception)
{
Source = source;
Result = result;
CaughtException = exception;
}
public TSource Source { get; private set; }
public TResult Result { get; private set; }
public Exception CaughtException { get; private set; }
}
}
}

View File

@ -8,7 +8,13 @@
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.1.0" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.2" />
@ -70,6 +76,9 @@
<None Update="Dockerfile"> <None Update="Dockerfile">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,2 @@
CardHolderName,CardNumber,CardType,City,Country,Email,Expiration,LastName,Name,PhoneNumber,UserName,ZipCode,State,Street,SecurityNumber,NormalizedEmail,NormalizedUserName,Password
DemoUser,4012888888881881,1,Redmond,U.S.,demouser@microsoft.com,12/20,DemoLastName,DemoUser,1234567890,demouser@microsoft.com,98052,WA,15703 NE 61st Ct,535,DEMOUSER@MICROSOFT.COM,DEMOUSER@MICROSOFT.COM,Pass@word1
1 CardHolderName CardNumber CardType City Country Email Expiration LastName Name PhoneNumber UserName ZipCode State Street SecurityNumber NormalizedEmail NormalizedUserName Password
2 DemoUser 4012888888881881 1 Redmond U.S. demouser@microsoft.com 12/20 DemoLastName DemoUser 1234567890 demouser@microsoft.com 98052 WA 15703 NE 61st Ct 535 DEMOUSER@MICROSOFT.COM DEMOUSER@MICROSOFT.COM Pass@word1

Binary file not shown.

View File

@ -153,7 +153,7 @@ namespace eShopOnContainers.Identity
//Seed Data //Seed Data
var hasher = new PasswordHasher<ApplicationUser>(); var hasher = new PasswordHasher<ApplicationUser>();
new ApplicationContextSeed(hasher).SeedAsync(app, loggerFactory).Wait(); new ApplicationContextSeed(hasher).SeedAsync(app, env, loggerFactory).Wait();
} }
private async Task InitializeGrantStoreAndConfiguration(IApplicationBuilder app) private async Task InitializeGrantStoreAndConfiguration(IApplicationBuilder app)

View File

@ -40,10 +40,7 @@
<br><div class="brand"></div> <br><div class="brand"></div>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<br /> <img class="text hidden-xs" src="~/images/main_footer_text.PNG" width="335" height="26" alt="footer text image" />
<br>
<br />
<div class="text hidden-xs">&copy; e-ShoponContainers. All right reserved</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -6,6 +6,7 @@
"MvcClient": "http://localhost:5100", "MvcClient": "http://localhost:5100",
"SpaClient": "http://localhost:5104", "SpaClient": "http://localhost:5104",
"XamarinCallback": "http://localhost:5105/xamarincallback", "XamarinCallback": "http://localhost:5105/xamarincallback",
"UseCustomizationData": true,
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {

View File

@ -476,11 +476,7 @@ footer {
} }
footer .text { footer .text {
text-align: right; margin-top: 55px;
width: 100%;
height: 100%;
color: #83D01B;
margin-top: 10px;
} }
.text { .text {

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 252 B

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ordering.API.Extensions
{
public static class LinqSelectExtensions
{
public static IEnumerable<SelectTryResult<TSource, TResult>> SelectTry<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
{
foreach (TSource element in enumerable)
{
SelectTryResult<TSource, TResult> returnedValue;
try
{
returnedValue = new SelectTryResult<TSource, TResult>(element, selector(element), null);
}
catch (Exception ex)
{
returnedValue = new SelectTryResult<TSource, TResult>(element, default(TResult), ex);
}
yield return returnedValue;
}
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.CaughtException));
}
public static IEnumerable<TResult> OnCaughtException<TSource, TResult>(this IEnumerable<SelectTryResult<TSource, TResult>> enumerable, Func<TSource, Exception, TResult> exceptionHandler)
{
return enumerable.Select(x => x.CaughtException == null ? x.Result : exceptionHandler(x.Source, x.CaughtException));
}
public class SelectTryResult<TSource, TResult>
{
internal SelectTryResult(TSource source, TResult result, Exception exception)
{
Source = source;
Result = result;
CaughtException = exception;
}
public TSource Source { get; private set; }
public TResult Result { get; private set; }
public Exception CaughtException { get; private set; }
}
}
}

View File

@ -8,40 +8,175 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using global::Ordering.API.Extensions;
public class OrderingContextSeed public class OrderingContextSeed
{ {
public static async Task SeedAsync(IApplicationBuilder applicationBuilder) public static async Task SeedAsync(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
var log = loggerFactory.CreateLogger("ordering seed");
var context = (OrderingContext)applicationBuilder var context = (OrderingContext)applicationBuilder
.ApplicationServices.GetService(typeof(OrderingContext)); .ApplicationServices.GetService(typeof(OrderingContext));
var settings = applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<OrderingSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
using (context) using (context)
{ {
context.Database.Migrate(); context.Database.Migrate();
if (!context.CardTypes.Any()) if (!context.CardTypes.Any())
{ {
context.CardTypes.Add(CardType.Amex); context.CardTypes.AddRange(useCustomizationData
context.CardTypes.Add(CardType.Visa); ? GetCardTypesFromFile(contentRootPath, log)
context.CardTypes.Add(CardType.MasterCard); : GetPredefinedCardTypes());
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
if (!context.OrderStatus.Any()) if (!context.OrderStatus.Any())
{ {
context.OrderStatus.Add(OrderStatus.Submitted); context.OrderStatus.AddRange(useCustomizationData
context.OrderStatus.Add(OrderStatus.AwaitingValidation); ? GetOrderStatusFromFile(contentRootPath, log)
context.OrderStatus.Add(OrderStatus.StockConfirmed); : GetPredefinedOrderStatus());
context.OrderStatus.Add(OrderStatus.Paid);
context.OrderStatus.Add(OrderStatus.Shipped);
context.OrderStatus.Add(OrderStatus.Cancelled);
} }
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
} }
static IEnumerable<CardType> GetCardTypesFromFile(string contentRootPath, ILogger log)
{
string csvFileCardTypes = Path.Combine(contentRootPath, "Setup", "CardTypes.csv");
if (!File.Exists(csvFileCardTypes))
{
return GetPredefinedCardTypes();
}
string[] csvheaders;
try
{
string[] requiredHeaders = { "CardType" };
csvheaders = GetHeaders(requiredHeaders, csvFileCardTypes);
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetPredefinedCardTypes();
}
int id = 1;
return File.ReadAllLines(csvFileCardTypes)
.Skip(1) // skip header column
.SelectTry(x => CreateCardType(x, ref id))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null);
}
static CardType CreateCardType(string value, ref int id)
{
if (String.IsNullOrEmpty(value))
{
throw new Exception("Orderstatus is null or empty");
}
return new CardType(id++, value.Trim('"').Trim());
}
private static IEnumerable<CardType> GetPredefinedCardTypes()
{
return new List<CardType>()
{
CardType.Amex,
CardType.Visa,
CardType.MasterCard
};
}
static IEnumerable<OrderStatus> GetOrderStatusFromFile(string contentRootPath, ILogger log)
{
string csvFileOrderStatus = Path.Combine(contentRootPath, "Setup", "OrderStatus.csv");
if (!File.Exists(csvFileOrderStatus))
{
return GetPredefinedOrderStatus();
}
string[] csvheaders;
try
{
string[] requiredHeaders = { "OrderStatus" };
csvheaders = GetHeaders(requiredHeaders, csvFileOrderStatus);
}
catch (Exception ex)
{
log.LogError(ex.Message);
return GetPredefinedOrderStatus();
}
int id = 1;
return File.ReadAllLines(csvFileOrderStatus)
.Skip(1) // skip header row
.SelectTry(x => CreateOrderStatus(x, ref id))
.OnCaughtException(ex => { log.LogError(ex.Message); return null; })
.Where(x => x != null);
}
static OrderStatus CreateOrderStatus(string value, ref int id)
{
if (String.IsNullOrEmpty(value))
{
throw new Exception("Orderstatus is null or empty");
}
return new OrderStatus(id++, value.Trim('"').Trim().ToLowerInvariant());
}
static IEnumerable<OrderStatus> GetPredefinedOrderStatus()
{
return new List<OrderStatus>()
{
OrderStatus.Submitted,
OrderStatus.AwaitingValidation,
OrderStatus.StockConfirmed,
OrderStatus.Paid,
OrderStatus.Shipped,
OrderStatus.Cancelled
};
}
static string[] GetHeaders(string[] requiredHeaders, string csvfile)
{
string[] csvheaders = File.ReadLines(csvfile).First().ToLowerInvariant().Split(',');
if (csvheaders.Count() != requiredHeaders.Count())
{
throw new Exception($"requiredHeader count '{ requiredHeaders.Count()}' is different then read header '{csvheaders.Count()}'");
}
foreach (var requiredHeader in requiredHeaders)
{
if (!csvheaders.Contains(requiredHeader))
{
throw new Exception($"does not contain required header '{requiredHeader}'");
}
}
return csvheaders;
}
} }
} }

View File

@ -16,6 +16,9 @@
<Content Include=".dockerignore;"> <Content Include=".dockerignore;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Include="Setup\**\*;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -73,6 +76,9 @@
<None Update="Dockerfile"> <None Update="Dockerfile">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="Setup\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,7 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API
{
public class OrderingSettings
{
public bool UseCustomizationData { get; set; }
}
}

View File

@ -0,0 +1,5 @@
CardType
Amex
Visa
MasterCard
Capital One
1 CardType
2 Amex
3 Visa
4 MasterCard
5 Capital One

View File

@ -0,0 +1,7 @@
OrderStatus
Submitted
AwaitingValidation
StockConfirmed
Paid
Shipped
Cancelled
1 OrderStatus
2 Submitted
3 AwaitingValidation
4 StockConfirmed
5 Paid
6 Shipped
7 Cancelled

View File

@ -87,6 +87,8 @@
ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request) ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
); );
services.Configure<OrderingSettings>(Configuration);
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
options.DescribeAllEnumsAsStrings(); options.DescribeAllEnumsAsStrings();
@ -159,7 +161,7 @@
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}); });
WaitForSqlAvailabilityAsync(loggerFactory, app).Wait(); WaitForSqlAvailabilityAsync(loggerFactory, app, env).Wait();
ConfigureEventBus(app); ConfigureEventBus(app);
var integrationEventLogContext = new IntegrationEventLogContext( var integrationEventLogContext = new IntegrationEventLogContext(
@ -200,13 +202,13 @@
} }
private async Task WaitForSqlAvailabilityAsync(ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0) private async Task WaitForSqlAvailabilityAsync(ILoggerFactory loggerFactory, IApplicationBuilder app, IHostingEnvironment env, int retries = 0)
{ {
var logger = loggerFactory.CreateLogger(nameof(Startup)); var logger = loggerFactory.CreateLogger(nameof(Startup));
var policy = CreatePolicy(retries, logger, nameof(WaitForSqlAvailabilityAsync)); var policy = CreatePolicy(retries, logger, nameof(WaitForSqlAvailabilityAsync));
await policy.ExecuteAsync(async () => await policy.ExecuteAsync(async () =>
{ {
await OrderingContextSeed.SeedAsync(app); await OrderingContextSeed.SeedAsync(app, env, loggerFactory);
}); });
} }

View File

@ -1,6 +1,7 @@
{ {
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
"IdentityUrl": "http://localhost:5105", "IdentityUrl": "http://localhost:5105",
"UseCustomizationData": true,
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {

View File

@ -13,6 +13,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
public string BasketUrl { get; set; } public string BasketUrl { get; set; }
public string MarketingUrl { get; set; } public string MarketingUrl { get; set; }
public Logging Logging { get; set; } public Logging Logging { get; set; }
public bool UseCustomizationData { get; set; }
} }
public class Connectionstrings public class Connectionstrings

View File

@ -0,0 +1,97 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.eShopOnContainers.WebMVC;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace WebMVC.Infrastructure
{
public class WebContextSeed
{
public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var log = loggerFactory.CreateLogger("WebMVC seed");
var settings = (AppSettings)applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
var webroot = env.WebRootPath;
if (useCustomizationData)
{
GetPreconfiguredImages(contentRootPath, webroot, log);
GetPreconfiguredCSS(contentRootPath, webroot, log);
}
}
static void GetPreconfiguredCSS(string contentRootPath, string webroot, ILogger log)
{
try
{
string overrideCssFile = Path.Combine(contentRootPath, "Setup", "override.css");
if (!File.Exists(overrideCssFile))
{
log.LogError($" override css file '{overrideCssFile}' does not exists.");
return;
}
string destinationFilename = Path.Combine(webroot, "css", "override.css");
File.Copy(overrideCssFile, destinationFilename, true );
}
catch (Exception ex)
{
log.LogError($"Exception in method GetPreconfiguredCSS WebMVC. Exception Message={ex.Message}");
}
}
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger log)
{
try
{
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
log.LogError($" zip file '{imagesZipFile}' does not exists.");
return;
}
string imagePath = Path.Combine(webroot, "images");
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in zip.Entries)
{
if (imageFiles.Contains(entry.Name))
{
string destinationFilename = Path.Combine(imagePath, entry.Name);
if (File.Exists(destinationFilename))
{
File.Delete(destinationFilename);
}
entry.ExtractToFile(destinationFilename);
}
else
{
log.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
}
}
}
}
catch ( Exception ex )
{
log.LogError($"Exception in method GetPreconfiguredImages WebMVC. Exception Message={ex.Message}");
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
.esh-catalog-button {
background-color: #83D01B; /* to override the style of this button ie. to make it red, use background-color: #FF001b; */
}

View File

@ -12,6 +12,7 @@ using Microsoft.Extensions.HealthChecks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using WebMVC.Infrastructure;
namespace Microsoft.eShopOnContainers.WebMVC namespace Microsoft.eShopOnContainers.WebMVC
{ {
@ -129,6 +130,9 @@ namespace Microsoft.eShopOnContainers.WebMVC
Scope = { "openid", "profile", "orders", "basket", "marketing" } Scope = { "openid", "profile", "orders", "basket", "marketing" }
}; };
//Seed Data
WebContextSeed.Seed(app, env, loggerFactory);
//Wait untill identity service is ready on compose. //Wait untill identity service is ready on compose.
app.UseOpenIdConnectAuthentication(oidcOptions); app.UseOpenIdConnectAuthentication(oidcOptions);

View File

@ -68,9 +68,9 @@
<img class="esh-orders_detail-image" src="@item.PictureUrl"> <img class="esh-orders_detail-image" src="@item.PictureUrl">
</section> </section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">@item.ProductName</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">@item.ProductName</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ @Math.Round(item.UnitPrice, 2)</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">@item.Units</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">@item.Units</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2)</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2).ToString("N2")</section>
</article> </article>
} }
</section> </section>

View File

@ -20,14 +20,14 @@
<input type="hidden" value="@item.ProductName" name=@("orderitems[" + i + "].ProductName") /> <input type="hidden" value="@item.ProductName" name=@("orderitems[" + i + "].ProductName") />
</section> </section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1"> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">
$ @item.UnitPrice $ @item.UnitPrice.ToString("N2")
<input type="hidden" value="@item.UnitPrice" name=@("orderitems[" + i + "].UnitPrice") /> <input type="hidden" value="@item.UnitPrice" name=@("orderitems[" + i + "].UnitPrice") />
</section> </section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1"> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">
@item.Units @item.Units
<input type="hidden" value="@item.Units" name=@("orderitems[" + i + "].Units") /> <input type="hidden" value="@item.Units" name=@("orderitems[" + i + "].Units") />
</section> </section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2)</section> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-2">$ @Math.Round(item.Units * item.UnitPrice, 2).ToString("N2")</section>
</article> </article>
} }
</section> </section>
@ -41,7 +41,7 @@
<article class="esh-orders_new-items row"> <article class="esh-orders_new-items row">
<section class="esh-orders_new-item col-xs-9"></section> <section class="esh-orders_new-item col-xs-9"></section>
<section class="esh-orders_new-item esh-orders_new-item--mark col-xs-2"> <section class="esh-orders_new-item esh-orders_new-item--mark col-xs-2">
$ @Model.Total $ @Model.Total.ToString("N2")
<input type="hidden" value="@Model.Total" name="Total"/> <input type="hidden" value="@Model.Total" name="Total"/>
</section> </section>
</article> </article>

View File

@ -23,12 +23,12 @@
<img class="esh-basket-image" src="@item.PictureUrl" /> <img class="esh-basket-image" src="@item.PictureUrl" />
</section> </section>
<section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section> <section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice</section> <section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2"> <section class="esh-basket-item esh-basket-item--middle col-xs-2">
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" /> <input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" />
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" /> <input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" />
</section> </section>
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2)</section> <section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
</div> </div>
<div class="row"> <div class="row">

View File

@ -19,12 +19,14 @@
<link rel="stylesheet" href="~/css/orders/orders.component.css" /> <link rel="stylesheet" href="~/css/orders/orders.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" /> <link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" /> <link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" />
</environment> </environment>
<environment names="Staging,Production"> <environment names="Staging,Production">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" />
</environment> </environment>
</head> </head>
<body> <body>
@ -56,7 +58,7 @@
</section> </section>
<section class="col-sm-6"> <section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShoponContainers. By Microsoft Corp. </div> <img class="esh-app-footer-text hidden-xs" src="~/images/main_footer_text.png" width="335" height="26" alt="footer text image" />
</section> </section>
</article> </article>

View File

@ -9,6 +9,24 @@
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Extensions\LinqSelectExtensions.cs" />
<Compile Remove="Services\CustomUIService.cs" />
<Compile Remove="Services\ICustomUIService.cs" />
</ItemGroup>
<ItemGroup>
<Content Remove="Views\Shared\_Footer.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Setup\override.css">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<!--<ItemGroup> <!--<ItemGroup>
<Compile Remove="wwwroot\lib\bootstrap\**" /> <Compile Remove="wwwroot\lib\bootstrap\**" />

View File

@ -7,6 +7,7 @@
"CallBackUrl": "http://localhost:5100/", "CallBackUrl": "http://localhost:5100/",
"IsClusterEnv": "False", "IsClusterEnv": "False",
"UseResilientHttp": "True", "UseResilientHttp": "True",
"UseCustomizationData": true,
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {

View File

@ -0,0 +1,42 @@
[
{
"outputFile": "wwwroot/css/orders/orders.component.css",
"inputFile": "wwwroot/css/orders/orders.component.scss"
},
{
"outputFile": "wwwroot/css/orders/orders-new/orders-new.component.css",
"inputFile": "wwwroot/css/orders/orders-new/orders-new.component.scss"
},
{
"outputFile": "wwwroot/css/orders/orders-detail/orders-detail.component.css",
"inputFile": "wwwroot/css/orders/orders-detail/orders-detail.component.scss"
},
{
"outputFile": "wwwroot/css/catalog/catalog.component.css",
"inputFile": "wwwroot/css/catalog/catalog.component.scss"
},
{
"outputFile": "wwwroot/css/basket/basket.component.css",
"inputFile": "wwwroot/css/basket/basket.component.scss"
},
{
"outputFile": "wwwroot/css/basket/basket-status/basket-status.component.css",
"inputFile": "wwwroot/css/basket/basket-status/basket-status.component.scss"
},
{
"outputFile": "wwwroot/css/shared/components/header/header.css",
"inputFile": "wwwroot/css/shared/components/header/header.scss"
},
{
"outputFile": "wwwroot/css/shared/components/identity/identity.css",
"inputFile": "wwwroot/css/shared/components/identity/identity.scss"
},
{
"outputFile": "wwwroot/css/shared/components/pager/pager.css",
"inputFile": "wwwroot/css/shared/components/pager/pager.scss"
},
{
"outputFile": "wwwroot/css/app.component.css",
"inputFile": "wwwroot/css/app.component.scss"
}
]

View File

@ -0,0 +1,49 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "expanded",
"Precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}

View File

@ -0,0 +1,58 @@
// Colors
$color-brand: #00A69C;
$color-brand-dark: darken($color-brand, 10%);
$color-brand-darker: darken($color-brand, 20%);
$color-brand-bright: lighten($color-brand, 10%);
$color-brand-brighter: lighten($color-brand, 20%);
$color-secondary: #83D01B;
$color-secondary-dark: darken($color-secondary, 5%);
$color-secondary-darker: darken($color-secondary, 20%);
$color-secondary-bright: lighten($color-secondary, 10%);
$color-secondary-brighter: lighten($color-secondary, 20%);
$color-background-dark: #333333;
$color-background-darker: #000000;
$color-background-bright: #EEEEFF;
$color-background-brighter: #FFFFFF;
$color-foreground-dark: #333333;
$color-foreground-darker: #000000;
$color-foreground-bright: #EEEEEE;
$color-foreground-brighter: #FFFFFF;
// Animations
$animation-speed-default: .35s;
$animation-speed-slow: .5s;
$animation-speed-fast: .15s;
// Fonts
$font-weight-light: 200;
$font-weight-semilight: 300;
$font-weight-normal: 400;
$font-weight-semibold: 600;
$font-weight-bold: 700;
$font-size-xs: .65rem; // 10.4px
$font-size-s: .85rem; // 13.6px
$font-size-m: 1rem; // 16px
$font-size-l: 1.25rem; // 20px
$font-size-xl: 1.5rem; // 24px
// Medias
$media-screen-xxs: 360px;
$media-screen-xs: 640px;
$media-screen-s: 768px;
$media-screen-m: 1024px;
$media-screen-l: 1280px;
$media-screen-xl: 1440px;
$media-screen-xxl: 1680px;
$media-screen-xxxl: 1920px;
// Borders
$border-light: 1px;
// Images
$image_path: '../../images/';
$image-main_banner: '#{$image_path}main_banner.png';
$image-arrow_down: '#{$image_path}arrow-down.png';

View File

@ -1,20 +1,14 @@
.esh-app-footer { .esh-app-footer {
background-color: #000000; background-color: #000000;
border-top: 1px solid #EEEEEE; border-top: 1px solid #EEEEEE;
margin-top: 2.5rem; margin-top: 2.5rem;
padding-bottom: 2.5rem; padding-bottom: 2.5rem;
padding-top: 2.5rem; padding-top: 2.5rem;
width: 100%; width: 100%;
} }
.esh-app-footer-brand { .esh-app-footer-brand {
height: 50px; height: 50px;
width: 230px; width: 230px;
} }
.esh-app-footer-text {
color: #83D01B;
line-height: 50px;
text-align: right;
width: 100%;
}

View File

@ -0,0 +1,23 @@
@import './variables';
.esh-app {
&-footer {
$margin: 2.5rem;
$padding: 2.5rem;
background-color: $color-background-darker;
border-top: $border-light solid $color-foreground-bright;
margin-top: $margin;
padding-bottom: $padding;
padding-top: $padding;
width: 100%;
$height: 50px;
&-brand {
height: $height;
width: 230px;
}
}
}

View File

@ -1,38 +1,39 @@
.esh-basketstatus { .esh-basketstatus {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
float: right; float: right;
position: relative; position: relative;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-basketstatus.is-disabled { .esh-basketstatus.is-disabled {
opacity: .5; opacity: .5;
pointer-events: none; pointer-events: none;
} }
.esh-basketstatus-image { .esh-basketstatus-image {
height: 36px; height: 36px;
margin-top: .5rem; margin-top: .5rem;
} }
.esh-basketstatus-badge { .esh-basketstatus-badge {
background-color: #83D01B; background-color: #83D01B;
border-radius: 50%; border-radius: 50%;
color: #FFFFFF; color: #FFFFFF;
display: block; display: block;
height: 1.5rem; height: 1.5rem;
left: 50%; left: 50%;
position: absolute; position: absolute;
text-align: center; text-align: center;
top: 0; top: 0;
transform: translateX(-38%); transform: translateX(-38%);
transition: all 0.35s; transition: all 0.35s;
width: 1.5rem; width: 1.5rem;
} }
.esh-basketstatus:hover .esh-basketstatus-badge { .esh-basketstatus:hover .esh-basketstatus-badge {
background-color: transparent; background-color: transparent;
color: #75b918; color: #75b918;
transition: all 0.35s; transition: all 0.35s;
} }

View File

@ -0,0 +1,41 @@
@import '../../variables';
.esh-basketstatus {
cursor: pointer;
display: inline-block;
float: right;
position: relative;
transition: all $animation-speed-default;
&.is-disabled {
opacity: .5;
pointer-events: none;
}
&-image {
height: 36px;
margin-top: .5rem;
}
&-badge {
$size: 1.5rem;
background-color: $color-secondary;
border-radius: 50%;
color: $color-foreground-brighter;
display: block;
height: $size;
left: 50%;
position: absolute;
text-align: center;
top: 0;
transform: translateX(-38%);
transition: all $animation-speed-default;
width: $size;
}
&:hover &-badge {
background-color: transparent;
color: $color-secondary-dark;
transition: all $animation-speed-default;
}
}

View File

@ -1,78 +1,79 @@
.esh-basket { .esh-basket {
min-height: 80vh; min-height: 80vh;
} }
.esh-basket-titles { .esh-basket-titles {
padding-bottom: 1rem; padding-bottom: 1rem;
padding-top: 2rem; padding-top: 2rem;
} }
.esh-basket-titles--clean { .esh-basket-titles--clean {
padding-bottom: 0; padding-bottom: 0;
padding-top: 0; padding-top: 0;
} }
.esh-basket-title { .esh-basket-title {
text-transform: uppercase; text-transform: uppercase;
} }
.esh-basket-items--border { .esh-basket-items--border {
border-bottom: 1px solid #EEEEEE; border-bottom: 1px solid #EEEEEE;
padding: .5rem 0; padding: .5rem 0;
} }
.esh-basket-items--border:last-of-type { .esh-basket-items--border:last-of-type {
border-color: transparent; border-color: transparent;
} }
.esh-basket-items-margin-left1 {
margin-left: 1px;
}
.esh-basket-item { .esh-basket-item {
font-size: 1rem; font-size: 1rem;
font-weight: 300; font-weight: 300;
} }
.esh-basket-item--middle { .esh-basket-item--middle {
line-height: 8rem; line-height: 8rem;
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
.esh-basket-item--middle { .esh-basket-item--middle {
line-height: 1rem; line-height: 1rem;
} }
} }
.esh-basket-item--mark { .esh-basket-item--mark {
color: #00A69C; color: #00A69C;
} }
.esh-basket-image { .esh-basket-image {
height: 8rem; height: 8rem;
} }
.esh-basket-input { .esh-basket-input {
line-height: 1rem; line-height: 1rem;
width: 100%; width: 100%;
} }
.esh-basket-checkout { .esh-basket-checkout {
border: none; background-color: #83D01B;
border-radius: 0; border: 0;
background-color: #83D01B; border-radius: 0;
color: #FFFFFF; color: #FFFFFF;
display: inline-block; display: inline-block;
font-size: 1rem; font-size: 1rem;
font-weight: 400; font-weight: 400;
margin-top: 1rem; margin-top: 1rem;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
text-align: center; text-align: center;
text-transform: uppercase; text-transform: uppercase;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-basket-checkout:hover { .esh-basket-checkout:hover {
background-color: #4a760f; background-color: #4a760f;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-basket-margin12{
margin-left: 12px;
}

View File

@ -0,0 +1,89 @@
@import '../variables';
@mixin margin-left($distance) {
margin-left: $distance;
}
.esh-basket {
min-height: 80vh;
&-titles {
padding-bottom: 1rem;
padding-top: 2rem;
&--clean {
padding-bottom: 0;
padding-top: 0;
}
}
&-title {
text-transform: uppercase;
}
&-items {
&--border {
border-bottom: $border-light solid $color-foreground-bright;
padding: .5rem 0;
&:last-of-type {
border-color: transparent;
}
}
&-margin-left1 {
@include margin-left(1px);
}
}
$item-height: 8rem;
&-item {
font-size: $font-size-m;
font-weight: $font-weight-semilight;
&--middle {
line-height: $item-height;
@media screen and (max-width: $media-screen-m) {
line-height: $font-size-m;
}
}
&--mark {
color: $color-brand;
}
}
&-image {
height: $item-height;
}
&-input {
line-height: 1rem;
width: 100%;
}
&-checkout {
background-color: $color-secondary;
border: 0;
border-radius: 0;
color: $color-foreground-brighter;
display: inline-block;
font-size: 1rem;
font-weight: $font-weight-normal;
margin-top: 1rem;
padding: 1rem 1.5rem;
text-align: center;
text-transform: uppercase;
transition: all $animation-speed-default;
&:hover {
background-color: $color-secondary-darker;
transition: all $animation-speed-default;
}
}
}

View File

@ -1,147 +1,149 @@
.esh-catalog-hero { .esh-catalog-hero {
background-image: url("../../images/main_banner.png"); background-image: url("../../images/main_banner.png");
background-size: cover; background-size: cover;
height: 260px; height: 260px;
width: 100%; width: 100%;
} }
.esh-catalog-title { .esh-catalog-title {
position: relative; position: relative;
top: 74.28571px; top: 74.28571px;
} }
.esh-catalog-filters { .esh-catalog-filters {
background-color: #00A69C; background-color: #00A69C;
height: 65px; height: 65px;
} }
.esh-catalog-filter { .esh-catalog-filter {
background-color: transparent; -webkit-appearance: none;
border-color: #00d9cc; background-color: transparent;
color: #FFFFFF; border-color: #00d9cc;
cursor: pointer; color: #FFFFFF;
margin-right: 1rem; cursor: pointer;
margin-top: .5rem; margin-right: 1rem;
outline-color: #83D01B; margin-top: .5rem;
padding-bottom: 0; min-width: 140px;
padding-left: 0.5rem; outline-color: #83D01B;
padding-right: 0.5rem; padding-bottom: 0;
padding-top: 1.5rem; padding-left: 0.5rem;
min-width: 140px; padding-right: 0.5rem;
-webkit-appearance: none; padding-top: 1.5rem;
} }
.esh-catalog-filter option { .esh-catalog-filter option {
background-color: #00A69C; background-color: #00A69C;
} }
.esh-catalog-label { .esh-catalog-label {
display: inline-block; display: inline-block;
position: relative; position: relative;
z-index: 0; z-index: 0;
} }
.esh-catalog-label::before { .esh-catalog-label::before {
color: rgba(255, 255, 255, 0.5); color: rgba(255, 255, 255, 0.5);
content: attr(data-title); content: attr(data-title);
font-size: 0.65rem; font-size: 0.65rem;
margin-top: 0.65rem; margin-left: 0.5rem;
margin-left: 0.5rem; margin-top: 0.65rem;
position: absolute; position: absolute;
text-transform: uppercase; text-transform: uppercase;
z-index: 1; z-index: 1;
} }
.esh-catalog-label::after { .esh-catalog-label::after {
background-image: url("../../images/arrow-down.png"); background-image: url("../../images/arrow-down.png");
height: 7px; content: '';
content: ''; height: 7px;
position: absolute; position: absolute;
right: 1.5rem; right: 1.5rem;
top: 2.5rem; top: 2.5rem;
width: 10px; width: 10px;
z-index: 1; z-index: 1;
} }
.esh-catalog-send { .esh-catalog-send {
background-color: #83D01B; background-color: #83D01B;
color: #FFFFFF; color: #FFFFFF;
cursor: pointer; cursor: pointer;
font-size: 1rem; font-size: 1rem;
transform: translateY(.5rem); margin-top: -1.5rem;
padding: 0.5rem; padding: 0.5rem;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-catalog-send:hover { .esh-catalog-send:hover {
background-color: #4a760f; background-color: #4a760f;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-catalog-items { .esh-catalog-items {
margin-top: 1rem; margin-top: 1rem;
} }
.esh-catalog-item { .esh-catalog-item {
text-align: center; margin-bottom: 1.5rem;
margin-bottom: 1.5rem; text-align: center;
width: 33%; width: 33%;
display: inline-block; display: inline-block;
float: none !important; float: none !important;
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
.esh-catalog-item { .esh-catalog-item {
width: 50%; width: 50%;
} }
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.esh-catalog-item { .esh-catalog-item {
width: 100%; width: 100%;
} }
} }
.esh-catalog-thumbnail { .esh-catalog-thumbnail {
max-width: 370px; max-width: 370px;
width: 100%; width: 100%;
} }
.esh-catalog-button { .esh-catalog-button {
background-color: #83D01B; background-color: #83D01B;
border: none; border: 0;
color: #FFFFFF; color: #FFFFFF;
cursor: pointer; cursor: pointer;
font-size: 1rem; font-size: 1rem;
height: 3rem; height: 3rem;
margin-top: 1rem; margin-top: 1rem;
transition: all 0.35s; transition: all 0.35s;
width: 80%; width: 80%;
} }
.esh-catalog-button.is-disabled {
opacity: .5;
pointer-events: none;
}
.esh-catalog-button:hover { .esh-catalog-button.is-disabled {
background-color: #4a760f; opacity: .5;
transition: all 0.35s; pointer-events: none;
} }
.esh-catalog-button:hover {
background-color: #4a760f;
transition: all 0.35s;
}
.esh-catalog-name { .esh-catalog-name {
font-size: 1rem; font-size: 1rem;
font-weight: 300; font-weight: 300;
margin-top: .5rem; margin-top: .5rem;
text-align: center; text-align: center;
text-transform: uppercase; text-transform: uppercase;
} }
.esh-catalog-price { .esh-catalog-price {
text-align: center; font-size: 28px;
font-weight: 900; font-weight: 900;
font-size: 28px; text-align: center;
}
.esh-catalog-price::before {
content: '$';
} }
.esh-catalog-price::before {
content: '$';
}

View File

@ -0,0 +1,154 @@
@import '../variables';
.esh-catalog {
$banner-height: 260px;
&-hero {
background-image: url($image-main_banner);
background-size: cover;
height: $banner-height;
width: 100%;
}
&-title {
position: relative;
top: $banner-height / 3.5;
}
$filter-height: 65px;
&-filters {
background-color: $color-brand;
height: $filter-height;
}
$filter-padding: .5rem;
&-filter {
-webkit-appearance: none;
background-color: transparent;
border-color: $color-brand-bright;
color: $color-foreground-brighter;
cursor: pointer;
margin-right: 1rem;
margin-top: .5rem;
min-width: 140px;
outline-color: $color-secondary;
padding-bottom: 0;
padding-left: $filter-padding;
padding-right: $filter-padding;
padding-top: $filter-padding * 3;
option {
background-color: $color-brand;
}
}
&-label {
display: inline-block;
position: relative;
z-index: 0;
&::before {
color: rgba($color-foreground-brighter, .5);
content: attr(data-title);
font-size: $font-size-xs;
margin-left: $filter-padding;
margin-top: $font-size-xs;
position: absolute;
text-transform: uppercase;
z-index: 1;
}
&::after {
background-image: url($image-arrow_down);
content: '';
height: 7px; //png height
position: absolute;
right: $filter-padding * 3;
top: $filter-padding * 5;
width: 10px; //png width
z-index: 1;
}
}
&-send {
background-color: $color-secondary;
color: $color-foreground-brighter;
cursor: pointer;
font-size: $font-size-m;
margin-top: -$filter-padding * 3;
padding: $filter-padding;
transition: all $animation-speed-default;
&:hover {
background-color: $color-secondary-darker;
transition: all $animation-speed-default;
}
}
&-items {
margin-top: 1rem;
}
&-item {
margin-bottom: 1.5rem;
text-align: center;
width: 33%;
display: inline-block;
float: none !important;
@media screen and (max-width: $media-screen-m) {
width: 50%;
}
@media screen and (max-width: $media-screen-s) {
width: 100%;
}
}
&-thumbnail {
max-width: 370px;
width: 100%;
}
&-button {
background-color: $color-secondary;
border: 0;
color: $color-foreground-brighter;
cursor: pointer;
font-size: $font-size-m;
height: 3rem;
margin-top: 1rem;
transition: all $animation-speed-default;
width: 80%;
&.is-disabled {
opacity: .5;
pointer-events: none;
}
&:hover {
background-color: $color-secondary-darker;
transition: all $animation-speed-default;
}
}
&-name {
font-size: $font-size-m;
font-weight: $font-weight-semilight;
margin-top: .5rem;
text-align: center;
text-transform: uppercase;
}
&-price {
font-size: 28px;
font-weight: 900;
text-align: center;
&::before {
content: '$';
}
}
}

View File

@ -1,52 +1,53 @@
.esh-orders_detail { .esh-orders_detail {
min-height: 80vh; min-height: 80vh;
} }
.esh-orders_detail-section { .esh-orders_detail-section {
padding: 1rem 0; padding: 1rem 0;
} }
.esh-orders_detail-section--right { .esh-orders_detail-section--right {
text-align: right; text-align: right;
} }
.esh-orders_detail-titles { .esh-orders_detail-titles {
padding-bottom: 1rem; padding-bottom: 1rem;
padding-top: 2rem; padding-top: 2rem;
} }
.esh-orders_detail-title { .esh-orders_detail-title {
text-transform: uppercase; text-transform: uppercase;
} }
.esh-orders_detail-items--border { .esh-orders_detail-items--border {
border-bottom: 1px solid #EEEEEE; border-bottom: 1px solid #EEEEEE;
padding: .5rem 0; padding: .5rem 0;
} }
.esh-orders_detail-items--border:last-of-type { .esh-orders_detail-items--border:last-of-type {
border-color: transparent; border-color: transparent;
} }
.esh-orders_detail-item { .esh-orders_detail-item {
font-size: 1rem; font-size: 1rem;
font-weight: 300; font-weight: 300;
} }
.esh-orders_detail-item--middle { .esh-orders_detail-item--middle {
line-height: 8rem; line-height: 8rem;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.esh-orders_detail-item--middle { .esh-orders_detail-item--middle {
line-height: 1rem; line-height: 1rem;
} }
} }
.esh-orders_detail-item--mark { .esh-orders_detail-item--mark {
color: #83D01B; color: #83D01B;
} }
.esh-orders_detail-image { .esh-orders_detail-image {
height: 8rem; height: 8rem;
} }

View File

@ -0,0 +1,56 @@
@import '../../variables';
.esh-orders_detail {
min-height: 80vh;
&-section {
padding: 1rem 0;
&--right {
text-align: right;
}
}
&-titles {
padding-bottom: 1rem;
padding-top: 2rem;
}
&-title {
text-transform: uppercase;
}
&-items {
&--border {
border-bottom: $border-light solid $color-foreground-bright;
padding: .5rem 0;
&:last-of-type {
border-color: transparent;
}
}
}
$item-height: 8rem;
&-item {
font-size: $font-size-m;
font-weight: $font-weight-semilight;
&--middle {
line-height: $item-height;
@media screen and (max-width: $media-screen-s) {
line-height: $font-size-m;
}
}
&--mark {
color: $color-secondary;
}
}
&-image {
height: $item-height;
}
}

View File

@ -1,91 +1,96 @@
.esh-orders_new { .esh-orders_new {
min-height: 80vh; min-height: 80vh;
} }
.esh-orders_new-header { .esh-orders_new-header {
background-color: #00A69C; background-color: #00A69C;
height: 4rem; height: 4rem;
} }
.esh-orders_new-back { .esh-orders_new-back {
color: rgba(255, 255, 255, 0.4); color: rgba(255, 255, 255, 0.4);
line-height: 4rem; line-height: 4rem;
text-decoration: none; text-decoration: none;
text-transform: uppercase; text-transform: uppercase;
transition: color 0.35s; transition: color 0.35s;
} }
.esh-orders_new-back:hover { .esh-orders_new-back:hover {
color: #FFFFFF; color: #FFFFFF;
transition: color 0.35s; transition: color 0.35s;
} }
.esh-orders_new-section { .esh-orders_new-section {
padding: 1rem 0; padding: 1rem 0;
} }
.esh-orders_new-section--right { .esh-orders_new-section--right {
text-align: right; text-align: right;
} }
.esh-orders_new-placeOrder { .esh-orders_new-placeOrder {
background-color: #83D01B; background-color: #83D01B;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
color: #FFFFFF; color: #FFFFFF;
display: inline-block; display: inline-block;
font-size: 1rem; font-size: 1rem;
font-weight: 400; font-weight: 400;
margin-top: 1rem; margin-top: 1rem;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
text-align: center; text-align: center;
text-transform: uppercase; text-transform: uppercase;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-orders_new-placeOrder:hover { .esh-orders_new-placeOrder:hover {
background-color: #4a760f; background-color: #4a760f;
transition: all 0.35s; transition: all 0.35s;
} }
.esh-orders_new-titles { .esh-orders_new-titles {
padding-bottom: 1rem; padding-bottom: 1rem;
padding-top: 2rem; padding-top: 2rem;
} }
.esh-orders_new-title { .esh-orders_new-title {
font-size: 1.25rem; font-size: 1.25rem;
text-transform: uppercase; text-transform: uppercase;
} }
.esh-orders_new-items--border { .esh-orders_new-items--border {
border-bottom: 1px solid #EEEEEE; border-bottom: 1px solid #EEEEEE;
padding: .5rem 0; padding: .5rem 0;
} }
.esh-orders_new-items--border:last-of-type { .esh-orders_new-items--border:last-of-type {
border-color: transparent; border-color: transparent;
} }
.esh-orders_new-item { .esh-orders_new-item {
font-size: 1rem; font-size: 1rem;
font-weight: 300; font-weight: 300;
} }
.esh-orders_new-item--middle { .esh-orders_new-item--middle {
line-height: 8rem; line-height: 8rem;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.esh-orders_new-item--middle { .esh-orders_new-item--middle {
line-height: 1rem; line-height: 1rem;
} }
} }
.esh-orders_new-item--mark { .esh-orders_new-item--mark {
color: #83D01B; color: #83D01B;
} }
.esh-orders_new-image { .esh-orders_new-image {
height: 8rem; height: 8rem;
} }
.esh-orders_new-alert {
margin-top: 10px;
}

View File

@ -0,0 +1,101 @@
@import '../../variables';
.esh-orders_new {
min-height: 80vh;
$header-height: 4rem;
&-header {
background-color: #00A69C;
height: $header-height;
}
&-back {
color: rgba($color-foreground-brighter, .4);
line-height: $header-height;
text-decoration: none;
text-transform: uppercase;
transition: color $animation-speed-default;
&:hover {
color: $color-foreground-brighter;
transition: color $animation-speed-default;
}
}
&-section {
padding: 1rem 0;
&--right {
text-align: right;
}
}
&-placeOrder {
background-color: $color-secondary;
border: 0;
border-radius: 0;
color: $color-foreground-brighter;
display: inline-block;
font-size: 1rem;
font-weight: $font-weight-normal;
margin-top: 1rem;
padding: 1rem 1.5rem;
text-align: center;
text-transform: uppercase;
transition: all $animation-speed-default;
&:hover {
background-color: $color-secondary-darker;
transition: all $animation-speed-default;
}
}
&-titles {
padding-bottom: 1rem;
padding-top: 2rem;
}
&-title {
font-size: $font-size-l;
text-transform: uppercase;
}
&-items {
&--border {
border-bottom: $border-light solid $color-foreground-bright;
padding: .5rem 0;
&:last-of-type {
border-color: transparent;
}
}
}
$item-height: 8rem;
&-item {
font-size: $font-size-m;
font-weight: $font-weight-semilight;
&--middle {
line-height: $item-height;
@media screen and (max-width: $media-screen-s) {
line-height: $font-size-m;
}
}
&--mark {
color: $color-secondary;
}
}
&-image {
height: $item-height;
}
&-alert {
margin-top: 10px;
}
}

View File

@ -1,74 +1,75 @@
.esh-orders { .esh-orders {
min-height: 80vh; min-height: 80vh;
overflow-x: hidden; overflow-x: hidden;
} }
.esh-orders-header { .esh-orders-header {
background-color: #00A69C; background-color: #00A69C;
height: 4rem; height: 4rem;
} }
.esh-orders-back { .esh-orders-back {
color: rgba(255, 255, 255, 0.4); color: rgba(255, 255, 255, 0.4);
line-height: 4rem; line-height: 4rem;
text-transform: uppercase; text-decoration: none;
text-decoration: none; text-transform: uppercase;
transition: color 0.35s; transition: color 0.35s;
} }
.esh-orders-back:hover { .esh-orders-back:hover {
color: #FFFFFF; color: #FFFFFF;
transition: color 0.35s; transition: color 0.35s;
} }
.esh-orders-titles { .esh-orders-titles {
padding-bottom: 1rem; padding-bottom: 1rem;
padding-top: 2rem; padding-top: 2rem;
} }
.esh-orders-title { .esh-orders-title {
text-transform: uppercase; text-transform: uppercase;
} }
.esh-orders-items { .esh-orders-items {
height: 2rem; height: 2rem;
line-height: 2rem; line-height: 2rem;
position: relative; position: relative;
} }
.esh-orders-items:nth-of-type(2n + 1):before { .esh-orders-items:nth-of-type(2n + 1):before {
background-color: #EEEEFF; background-color: #EEEEFF;
content: ''; content: '';
height: 100%; height: 100%;
left: 0; left: 0;
margin-left: -100vw; margin-left: -100vw;
position: absolute; position: absolute;
top: 0; top: 0;
width: 200vw; width: 200vw;
z-index: -1; z-index: -1;
} }
.esh-orders-item { .esh-orders-item {
font-weight: 300; font-weight: 300;
} }
.esh-orders-item--hover { .esh-orders-item--hover {
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
} }
.esh-orders-items:hover .esh-orders-item--hover { .esh-orders-items:hover .esh-orders-item--hover {
opacity: 1; opacity: 1;
pointer-events: all; pointer-events: all;
} }
.esh-orders-link { .esh-orders-link {
color: #83D01B; color: #83D01B;
text-decoration: none; text-decoration: none;
transition: color 0.35s; transition: color 0.35s;
}
.esh-orders-link:hover {
color: #75b918;
transition: color 0.35s;
} }
.esh-orders-link:hover {
color: #75b918;
transition: color 0.35s;
}

View File

@ -0,0 +1,81 @@
@import '../variables';
.esh-orders {
min-height: 80vh;
overflow-x: hidden;
$header-height: 4rem;
&-header {
background-color: #00A69C;
height: $header-height;
}
&-back {
color: rgba($color-foreground-brighter, .4);
line-height: $header-height;
text-decoration: none;
text-transform: uppercase;
transition: color $animation-speed-default;
&:hover {
color: $color-foreground-brighter;
transition: color $animation-speed-default;
}
}
&-titles {
padding-bottom: 1rem;
padding-top: 2rem;
}
&-title {
text-transform: uppercase;
}
&-items {
$height: 2rem;
height: $height;
line-height: $height;
position: relative;
&:nth-of-type(2n + 1) {
&:before {
background-color: $color-background-bright;
content: '';
height: 100%;
left: 0;
margin-left: -100vw;
position: absolute;
top: 0;
width: 200vw;
z-index: -1;
}
}
}
&-item {
font-weight: $font-weight-semilight;
&--hover {
opacity: 0;
pointer-events: none;
}
}
&-items:hover &-item--hover {
opacity: 1;
pointer-events: all;
}
&-link {
color: $color-secondary;
text-decoration: none;
transition: color $animation-speed-default;
&:hover {
color: $color-secondary-dark;
transition: color $animation-speed-default;
}
}
}

View File

@ -0,0 +1,3 @@
.esh-catalog-button {
background-color: #83D01B; /* to override the style of this button ie. to make it red, use background-color: #FF001b; */
}

View File

@ -1,31 +1,18 @@
.esh-header { .esh-header {
background-color: #00A69C; background-color: #00A69C;
height: 4rem; height: 4rem;
} }
.esh-header-title {
color: rgba(255, 255, 255, 0.5) !important;
line-height: 4rem;
text-transform: uppercase;
text-decoration: none;
transition: color 0.35s;
margin-right: 15px;
}
.esh-header-title:hover {
color: #FFFFFF !important;
transition: color 0.35s;
}
.esh-header-back { .esh-header-back {
color: rgba(255, 255, 255, 0.5) !important; color: rgba(255, 255, 255, 0.5);
line-height: 4rem; line-height: 4rem;
text-transform: uppercase; text-decoration: none;
text-decoration: none; text-transform: uppercase;
transition: color 0.35s; transition: color 0.35s;
}
.esh-header-back:hover {
color: #FFFFFF;
transition: color 0.35s;
} }
.esh-header-back:hover {
color: #FFFFFF !important;
transition: color 0.35s;
}

View File

@ -0,0 +1,21 @@
@import '../../../variables';
.esh-header {
$header-height: 4rem;
background-color: $color-brand;
height: $header-height;
&-back {
color: rgba($color-foreground-brighter, .5);
line-height: $header-height;
text-decoration: none;
text-transform: uppercase;
transition: color $animation-speed-default;
&:hover {
color: $color-foreground-brighter;
transition: color $animation-speed-default;
}
}
}

View File

@ -1,57 +1,57 @@
.esh-identity { .esh-identity {
line-height: 3rem; line-height: 3rem;
position: relative; position: relative;
text-align: right; text-align: right;
} }
.esh-identity-section { .esh-identity-section {
display: inline-block; display: inline-block;
width: 100%; width: 100%;
} }
.esh-identity-name { .esh-identity-name {
display: inline-block; display: inline-block;
} }
.esh-identity-name--upper { .esh-identity-name--upper {
text-transform: uppercase; text-transform: uppercase;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.esh-identity-name { .esh-identity-name {
font-size: 0.85rem; font-size: 0.85rem;
} }
} }
.esh-identity-image { .esh-identity-image {
display: inline-block; display: inline-block;
} }
.esh-identity-drop { .esh-identity-drop {
background: #FFFFFF; background: #FFFFFF;
height: 0rem; height: 0;
min-width: 14rem; min-width: 14rem;
right: 0; overflow: hidden;
overflow: hidden; padding: .5rem;
padding: .5rem; position: absolute;
position: absolute; right: 0;
top: 2.5rem; top: 2.5rem;
transition: height 0.35s; transition: height 0.35s;
} }
.esh-identity:hover .esh-identity-drop { .esh-identity:hover .esh-identity-drop {
border: 1px solid #EEEEEE; border: 1px solid #EEEEEE;
height: 9.5rem; height: 7rem;
transition: height 0.35s; transition: height 0.35s;
} }
.esh-identity-item { .esh-identity-item {
cursor: pointer; cursor: pointer;
display: block; transition: color 0.35s;
transition: color 0.35s; }
.esh-identity-item:hover {
color: #75b918;
transition: color 0.35s;
} }
.esh-identity-item:hover {
color: #75b918;
transition: color 0.35s;
}

View File

@ -0,0 +1,56 @@
@import '../../../variables';
.esh-identity {
line-height: 3rem;
position: relative;
text-align: right;
&-section {
display: inline-block;
width: 100%;
}
&-name {
display: inline-block;
&--upper {
text-transform: uppercase;
}
@media screen and (max-width: $media-screen-s) {
font-size: $font-size-s;
}
}
&-image {
display: inline-block;
}
&-drop {
background: $color-background-brighter;
height: 0;
min-width: 14rem;
overflow: hidden;
padding: .5rem;
position: absolute;
right: 0;
top: 2.5rem;
transition: height $animation-speed-default;
}
&:hover &-drop {
border: $border-light solid $color-foreground-bright;
height: 7rem;
transition: height $animation-speed-default;
}
&-item {
cursor: pointer;
transition: color $animation-speed-default;
&:hover {
color: $color-secondary-dark;
transition: color $animation-speed-default;
}
}
}

View File

@ -1,34 +1,35 @@
.esh-pager-wrapper { .esh-pager-wrapper {
padding-top: 1rem; padding-top: 1rem;
text-align: center; text-align: center;
} }
.esh-pager-item { .esh-pager-item {
margin: 0 5vw; margin: 0 5vw;
}
.esh-pager-item.is-disabled {
opacity: 0;
pointer-events: none;
} }
.esh-pager-item--navigable { .esh-pager-item--navigable {
display: inline-block; cursor: pointer;
cursor: pointer; display: inline-block;
} }
.esh-pager-item--navigable.is-disabled { .esh-pager-item--navigable:hover {
opacity: 0; color: #83D01B;
pointer-events: none; }
}
.esh-pager-item--navigable:hover {
color: #83D01B;
}
@media screen and (max-width: 1280px) { @media screen and (max-width: 1280px) {
.esh-pager-item { .esh-pager-item {
font-size: 0.85rem; font-size: 0.85rem;
} }
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
.esh-pager-item { .esh-pager-item {
margin: 0 4vw; margin: 0 2.5vw;
} }
} }

View File

@ -0,0 +1,36 @@
@import '../../../variables';
.esh-pager {
&-wrapper {
padding-top: 1rem;
text-align: center;
}
&-item {
$margin: 5vw;
margin: 0 $margin;
&.is-disabled {
opacity: 0;
pointer-events: none;
}
&--navigable {
cursor: pointer;
display: inline-block;
&:hover {
color: $color-secondary;
}
}
@media screen and (max-width: $media-screen-l) {
font-size: $font-size-s;
}
@media screen and (max-width: $media-screen-m) {
margin: 0 $margin / 2;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 KiB

After

Width:  |  Height:  |  Size: 851 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 252 B

View File

@ -13,5 +13,6 @@ namespace eShopOnContainers.WebSPA
public string IdentityUrl { get; set; } public string IdentityUrl { get; set; }
public string BasketUrl { get; set; } public string BasketUrl { get; set; }
public string MarketingUrl { get; set; } public string MarketingUrl { get; set; }
public bool UseCustomizationData { get; set; }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -51,3 +51,8 @@ $media-screen-xxxl: 1920px;
// Borders // Borders
$border-light: 1px; $border-light: 1px;
// Images
$image_path: '/assets/images/';
$image-main_banner: '#{$image_path}main_banner.png';
$image-arrow_down: '#{$image_path}arrow-down.png';

View File

@ -32,7 +32,7 @@
</section> </section>
<section class="col-sm-6"> <section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShoponContainers. All right reserved </div> <img class="esh-app-footer-text hidden-xs" src="assets/images/main_footer_text.png" width="335" height="26" alt="footer text image" />
</section> </section>
</article> </article>

View File

@ -19,11 +19,5 @@
width: 230px; width: 230px;
} }
&-text {
color: $color-secondary;
line-height: $height;
text-align: right;
width: 100%;
}
} }
} }

View File

@ -17,7 +17,7 @@
<img class="esh-basket-image" src="{{item.pictureUrl}}" /> <img class="esh-basket-image" src="{{item.pictureUrl}}" />
</section> </section>
<section class="esh-basket-item esh-basket-item--middle col-xs-3">{{item.productName}}</section> <section class="esh-basket-item esh-basket-item--middle col-xs-3">{{item.productName}}</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ {{item.unitPrice}}</section> <section class="esh-basket-item esh-basket-item--middle col-xs-2">$ {{item.unitPrice | number:'.2-2'}}</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2"> <section class="esh-basket-item esh-basket-item--middle col-xs-2">
<input class="esh-basket-input" <input class="esh-basket-input"
type="number" type="number"
@ -25,7 +25,7 @@
[(ngModel)]="item.quantity" [(ngModel)]="item.quantity"
(change)="itemQuantityChanged(item)" /> (change)="itemQuantityChanged(item)" />
</section> </section>
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ {{item.unitPrice * item.quantity}}</section> <section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ {{(item.unitPrice * item.quantity) | number:'.2-2'}}</section>
</article> </article>
<br/> <br/>
<div class="esh-basket-items-margin-left1 row"> <div class="esh-basket-items-margin-left1 row">
@ -42,7 +42,7 @@
<article class="esh-basket-items row"> <article class="esh-basket-items row">
<section class="esh-basket-item col-xs-9"></section> <section class="esh-basket-item col-xs-9"></section>
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ {{totalPrice}}</section> <section class="esh-basket-item esh-basket-item--mark col-xs-2">$ {{totalPrice | number:'.2-2'}}</section>
</article> </article>
<article class="esh-basket-items row"> <article class="esh-basket-items row">

View File

@ -37,7 +37,7 @@
<span>{{item.name}}</span> <span>{{item.name}}</span>
</div> </div>
<div class="esh-catalog-price"> <div class="esh-catalog-price">
<span>{{item.price}}</span> <span>{{item.price | number:'.2-2'}}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@
$banner-height: 260px; $banner-height: 260px;
&-hero { &-hero {
background-image: url('../../assets/images/main_banner.png'); background-image: url($image-main_banner);
background-size: cover; background-size: cover;
height: $banner-height; height: $banner-height;
width: 100%; width: 100%;
@ -61,7 +61,7 @@
} }
&::after { &::after {
background-image: url('../../assets/images/arrow-down.png'); background-image: url($image-arrow_down);
content: ''; content: '';
height: 7px; //png height height: 7px; //png height
position: absolute; position: absolute;

View File

@ -57,9 +57,9 @@
<img class="esh-orders_detail-image" src="{{item.pictureurl}}"> <img class="esh-orders_detail-image" src="{{item.pictureurl}}">
</section> </section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">{{item.productname}}</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-4">{{item.productname}}</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ {{item.unitprice}}</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">$ {{item.unitprice | number:'.2-2'}}</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">{{item.units}}</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-1">{{item.units}}</section>
<section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ {{item.units * item.unitprice}}</section> <section class="esh-orders_detail-item esh-orders_detail-item--middle col-xs-2">$ {{(item.units * item.unitprice) | number:'.2-2'}}</section>
</article> </article>
</section> </section>
@ -71,7 +71,7 @@
<article class="esh-orders_detail-items row"> <article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-9"></section> <section class="esh-orders_detail-item col-xs-9"></section>
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ {{order.total}}</section> <section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ {{order.total | number:'.2-2'}}</section>
</article> </article>
</section> </section>
</div> </div>

View File

@ -86,9 +86,9 @@
<img class="esh-orders_new-image" src="{{item.pictureurl}}"> <img class="esh-orders_new-image" src="{{item.pictureurl}}">
</section> </section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-4">{{item.productname}}</section> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-4">{{item.productname}}</section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">$ {{item.unitprice}}</section> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">$ {{item.unitprice | number:'.2-2'}}</section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">{{item.units}}</section> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-1">{{item.units}}</section>
<section class="esh-orders_new-item esh-orders_new-item--middle col-xs-2">$ {{item.units * item.unitprice}}</section> <section class="esh-orders_new-item esh-orders_new-item--middle col-xs-2">$ {{(item.units * item.unitprice) | number:'.2-2'}}</section>
</article> </article>
</section> </section>
@ -100,7 +100,7 @@
<article class="esh-orders_new-items row"> <article class="esh-orders_new-items row">
<section class="esh-orders_new-item col-xs-9"></section> <section class="esh-orders_new-item col-xs-9"></section>
<section class="esh-orders_new-item esh-orders_new-item--mark col-xs-2">$ {{order.total}}</section> <section class="esh-orders_new-item esh-orders_new-item--mark col-xs-2">$ {{order.total | number:'.2-2'}}</section>
</article> </article>
</section> </section>
<section class="esh-orders_new-section"> <section class="esh-orders_new-section">

View File

@ -0,0 +1,73 @@
using eShopOnContainers.WebSPA;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace WebSPA.Infrastructure
{
public class WebContextSeed
{
public static void Seed(IApplicationBuilder applicationBuilder, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var log = loggerFactory.CreateLogger("WebSPA seed");
var settings = (AppSettings)applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
var contentRootPath = env.ContentRootPath;
var webroot = env.WebRootPath;
if (useCustomizationData)
{
GetPreconfiguredImages(contentRootPath, webroot, log);
}
}
static void GetPreconfiguredImages(string contentRootPath, string webroot, ILogger log)
{
try
{
string imagesZipFile = Path.Combine(contentRootPath, "Setup", "images.zip");
if (!File.Exists(imagesZipFile))
{
log.LogError($" zip file '{imagesZipFile}' does not exists.");
return;
}
string imagePath = Path.Combine(webroot, "assets", "images");
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in zip.Entries)
{
if (imageFiles.Contains(entry.Name))
{
string destinationFilename = Path.Combine(imagePath, entry.Name);
if (File.Exists(destinationFilename))
{
File.Delete(destinationFilename);
}
entry.ExtractToFile(destinationFilename);
}
else
{
log.LogWarning($"Skip file '{entry.Name}' in zipfile '{imagesZipFile}'");
}
}
}
}
catch (Exception ex)
{
log.LogError($"Exception in method GetPreconfiguredImages WebSPA. Exception Message={ex.Message}");
}
}
}
}

Binary file not shown.

View File

@ -11,6 +11,7 @@ using Microsoft.Extensions.HealthChecks;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using eShopOnContainers.WebSPA; using eShopOnContainers.WebSPA;
using Microsoft.eShopOnContainers.BuildingBlocks; using Microsoft.eShopOnContainers.BuildingBlocks;
using WebSPA.Infrastructure;
namespace eShopConContainers.WebSPA namespace eShopConContainers.WebSPA
{ {
@ -99,6 +100,9 @@ namespace eShopConContainers.WebSPA
// await next.Invoke(); // await next.Invoke();
// }); // });
//Seed Data
WebContextSeed.Seed(app, env, loggerFactory);
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {
await next(); await next();

View File

@ -16,6 +16,9 @@
<ItemGroup> <ItemGroup>
<Compile Remove="node_modules\**\*;Client\**\*" /> <Compile Remove="node_modules\**\*;Client\**\*" />
<Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.json;"> <Content Update="appsettings.json;">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>

View File

@ -5,6 +5,7 @@
"IdentityUrl": "http://localhost:5105", "IdentityUrl": "http://localhost:5105",
"MarketingUrl": "http://localhost:5110", "MarketingUrl": "http://localhost:5110",
"CallBackUrl": "http://localhost:5104/", "CallBackUrl": "http://localhost:5104/",
"UseCustomizationData": true,
"IsClusterEnv": "False", "IsClusterEnv": "False",
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,