Merge branch 'marketingcampaign' into dev
# Conflicts: # eShopOnContainers-ServicesAndWebApps.sln
This commit is contained in:
commit
5d3d27fce4
@ -21,6 +21,6 @@ try {
|
|||||||
Write-Host "Rule found"
|
Write-Host "Rule found"
|
||||||
}
|
}
|
||||||
catch [Exception] {
|
catch [Exception] {
|
||||||
New-NetFirewallRule -DisplayName eShopOnContainers-Inbound -Confirm -Description "eShopOnContainers Inbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5105 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound
|
New-NetFirewallRule -DisplayName eShopOnContainers-Inbound -Confirm -Description "eShopOnContainers Inbound Rule for port range 5100-5110" -LocalAddress Any -LocalPort 5100-5110 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Inbound
|
||||||
New-NetFirewallRule -DisplayName eShopOnContainers-Outbound -Confirm -Description "eShopOnContainers Outbound Rule for port range 5100-5105" -LocalAddress Any -LocalPort 5100-5105 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound
|
New-NetFirewallRule -DisplayName eShopOnContainers-Outbound -Confirm -Description "eShopOnContainers Outbound Rule for port range 5100-5110" -LocalAddress Any -LocalPort 5100-5110 -Protocol tcp -RemoteAddress Any -RemotePort Any -Direction Outbound
|
||||||
}
|
}
|
@ -49,6 +49,15 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5102:80"
|
- "5102:80"
|
||||||
|
|
||||||
|
marketing.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;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.
|
||||||
|
ports:
|
||||||
|
- "5110:80"
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
@ -94,4 +103,4 @@ services:
|
|||||||
- mvc=http://webmvc/hc
|
- mvc=http://webmvc/hc
|
||||||
- spa=http://webspa/hc
|
- spa=http://webspa/hc
|
||||||
ports:
|
ports:
|
||||||
- "5107:80"
|
- "5107:80"
|
@ -54,6 +54,15 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5102:80"
|
- "5102:80"
|
||||||
|
|
||||||
|
marketing.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;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.
|
||||||
|
ports:
|
||||||
|
- "5110:80"
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Production
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
@ -61,6 +61,22 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||||
|
|
||||||
|
marketing.api:
|
||||||
|
image: eshop/marketing.api:dev
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
source: ${DOCKER_BUILD_SOURCE}
|
||||||
|
environment:
|
||||||
|
- DOTNET_USE_POLLING_FILE_WATCHER=1
|
||||||
|
volumes:
|
||||||
|
- ./src/Services/Marketing/Marketing.API:/app
|
||||||
|
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||||
|
- ~/clrdbg:/clrdbg:ro
|
||||||
|
entrypoint: tail -f /dev/null
|
||||||
|
labels:
|
||||||
|
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||||
|
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
image: eshop/webspa:dev
|
image: eshop/webspa:dev
|
||||||
build:
|
build:
|
||||||
@ -105,3 +121,4 @@ services:
|
|||||||
entrypoint: tail -f /dev/null
|
entrypoint: tail -f /dev/null
|
||||||
labels:
|
labels:
|
||||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||||
|
|
||||||
|
@ -41,6 +41,16 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||||
|
|
||||||
|
marketing.api:
|
||||||
|
build:
|
||||||
|
args:
|
||||||
|
source: ${DOCKER_BUILD_SOURCE}
|
||||||
|
volumes:
|
||||||
|
- ~/clrdbg:/clrdbg:ro
|
||||||
|
entrypoint: tail -f /dev/null
|
||||||
|
labels:
|
||||||
|
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
build:
|
build:
|
||||||
args:
|
args:
|
||||||
|
@ -36,6 +36,15 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- sql.data
|
- sql.data
|
||||||
|
|
||||||
|
marketing.api:
|
||||||
|
image: eshop/marketing.api
|
||||||
|
build:
|
||||||
|
context: ./src/Services/Marketing/Marketing.API
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
- identity.api
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
image: eshop/webspa
|
image: eshop/webspa
|
||||||
build:
|
build:
|
||||||
@ -74,4 +83,4 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./src/Web/WebStatus
|
context: ./src/Web/WebStatus
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|
||||||
|
@ -80,6 +80,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataProtection", "DataProte
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataProtection", "src\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj", "{23A33F9B-7672-426D-ACF9-FF8436ADC81A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataProtection", "src\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj", "{23A33F9B-7672-426D-ACF9-FF8436ADC81A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Marketing", "Marketing", "{A5260DE0-1FDD-467E-9CC1-A028AB081CEE}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||||
@ -1054,6 +1058,54 @@ Global
|
|||||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.Build.0 = Release|Any CPU
|
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.ActiveCfg = Release|Any CPU
|
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.Build.0 = Release|Any CPU
|
{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -1090,6 +1142,8 @@ Global
|
|||||||
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{22A0F9C1-2D4A-4107-95B7-8459E6688BC5} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
{4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
{89D80DF1-32E1-4AAF-970F-DA0AA6881F9D} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||||
|
{A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||||
|
{DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE}
|
||||||
{88B22DBB-AA8F-4290-A454-2C109352C345} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
{88B22DBB-AA8F-4290-A454-2C109352C345} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||||
{23A33F9B-7672-426D-ACF9-FF8436ADC81A} = {88B22DBB-AA8F-4290-A454-2C109352C345}
|
{23A33F9B-7672-426D-ACF9-FF8436ADC81A} = {88B22DBB-AA8F-4290-A454-2C109352C345}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
@ -12,7 +12,8 @@ namespace Identity.API.Configuration
|
|||||||
return new List<ApiResource>
|
return new List<ApiResource>
|
||||||
{
|
{
|
||||||
new ApiResource("orders", "Orders Service"),
|
new ApiResource("orders", "Orders Service"),
|
||||||
new ApiResource("basket", "Basket Service")
|
new ApiResource("basket", "Basket Service"),
|
||||||
|
new ApiResource("marketing", "Marketing Service")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
src/Services/Marketing/Marketing.API/.dockerignore
Normal file
3
src/Services/Marketing/Marketing.API/.dockerignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*
|
||||||
|
!obj/Docker/publish/*
|
||||||
|
!obj/Docker/empty/
|
@ -0,0 +1,151 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Dto;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
[Route("api/v1/[controller]")]
|
||||||
|
[Authorize]
|
||||||
|
public class CampaignsController : Controller
|
||||||
|
{
|
||||||
|
private readonly MarketingContext _context;
|
||||||
|
|
||||||
|
public CampaignsController(MarketingContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAllCampaigns()
|
||||||
|
{
|
||||||
|
var campaignList = await _context.Campaigns
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (campaignList is null)
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
var campaignDtoList = MapCampaignModelListToDtoList(campaignList);
|
||||||
|
|
||||||
|
return Ok(campaignDtoList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
public async Task<IActionResult> GetCampaignById(int id)
|
||||||
|
{
|
||||||
|
var campaign = await _context.Campaigns
|
||||||
|
.SingleOrDefaultAsync(c => c.Id == id);
|
||||||
|
|
||||||
|
if (campaign is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var campaignDto = MapCampaignModelToDto(campaign);
|
||||||
|
|
||||||
|
return Ok(campaignDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> CreateCampaign([FromBody] CampaignDTO campaignDto)
|
||||||
|
{
|
||||||
|
if (campaignDto is null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var campaign = MapCampaignDtoToModel(campaignDto);
|
||||||
|
|
||||||
|
await _context.Campaigns.AddAsync(campaign);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetCampaignById), new { id = campaign.Id }, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id:int}")]
|
||||||
|
public async Task<IActionResult> UpdateCampaign(int id, [FromBody] CampaignDTO campaignDto)
|
||||||
|
{
|
||||||
|
if (id < 1 || campaignDto is null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var campaignToUpdate = await _context.Campaigns.FindAsync(id);
|
||||||
|
if (campaignToUpdate is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
campaignToUpdate.Description = campaignDto.Description;
|
||||||
|
campaignToUpdate.From = campaignDto.From;
|
||||||
|
campaignToUpdate.To = campaignDto.To;
|
||||||
|
campaignToUpdate.Url = campaignDto.Url;
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignToUpdate.Id }, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id:int}")]
|
||||||
|
public async Task<IActionResult> Delete(int id)
|
||||||
|
{
|
||||||
|
if (id < 1)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var campaignToDelete = await _context.Campaigns.FindAsync(id);
|
||||||
|
if (campaignToDelete is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Campaigns.Remove(campaignToDelete);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private List<CampaignDTO> MapCampaignModelListToDtoList(List<Campaign> campaignList)
|
||||||
|
{
|
||||||
|
var campaignDtoList = new List<CampaignDTO>();
|
||||||
|
|
||||||
|
campaignList.ForEach(campaign => campaignDtoList
|
||||||
|
.Add(MapCampaignModelToDto(campaign)));
|
||||||
|
|
||||||
|
return campaignDtoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CampaignDTO MapCampaignModelToDto(Campaign campaign)
|
||||||
|
{
|
||||||
|
return new CampaignDTO
|
||||||
|
{
|
||||||
|
Id = campaign.Id,
|
||||||
|
Description = campaign.Description,
|
||||||
|
From = campaign.From,
|
||||||
|
To = campaign.To,
|
||||||
|
Url = campaign.Url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Campaign MapCampaignDtoToModel(CampaignDTO campaignDto)
|
||||||
|
{
|
||||||
|
return new Campaign
|
||||||
|
{
|
||||||
|
Id = campaignDto.Id,
|
||||||
|
Description = campaignDto.Description,
|
||||||
|
From = campaignDto.From,
|
||||||
|
To = campaignDto.To,
|
||||||
|
Url = campaignDto.Url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
// GET: /<controller>/
|
||||||
|
public class HomeController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return new RedirectResult("~/swagger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Dto;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Model;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public class LocationsController : Controller
|
||||||
|
{
|
||||||
|
private readonly MarketingContext _context;
|
||||||
|
|
||||||
|
public LocationsController(MarketingContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/v1/campaigns/{campaignId:int}/locations/{userLocationRuleId:int}")]
|
||||||
|
public IActionResult GetLocationByCampaignAndLocationRuleId(int campaignId,
|
||||||
|
int userLocationRuleId)
|
||||||
|
{
|
||||||
|
if (campaignId < 1 || userLocationRuleId < 1)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var location = _context.Rules
|
||||||
|
.OfType<UserLocationRule>()
|
||||||
|
.SingleOrDefault(c => c.CampaignId == campaignId && c.Id == userLocationRuleId);
|
||||||
|
|
||||||
|
if (location is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var locationDto = MapUserLocationRuleModelToDto(location);
|
||||||
|
|
||||||
|
return Ok(locationDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/v1/campaigns/{campaignId:int}/locations")]
|
||||||
|
public IActionResult GetAllLocationsByCampaignId(int campaignId)
|
||||||
|
{
|
||||||
|
if (campaignId < 1)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var locationList = _context.Rules
|
||||||
|
.OfType<UserLocationRule>()
|
||||||
|
.Where(c => c.CampaignId == campaignId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if(locationList is null)
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
var locationDtoList = MapUserLocationRuleModelListToDtoList(locationList);
|
||||||
|
|
||||||
|
return Ok(locationDtoList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/v1/campaigns/{campaignId:int}/locations")]
|
||||||
|
public async Task<IActionResult> CreateLocation(int campaignId,
|
||||||
|
[FromBody] UserLocationRuleDTO locationRuleDto)
|
||||||
|
{
|
||||||
|
if (campaignId < 1 || locationRuleDto is null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var locationRule = MapUserLocationRuleDtoToModel(locationRuleDto);
|
||||||
|
locationRule.CampaignId = campaignId;
|
||||||
|
|
||||||
|
await _context.Rules.AddAsync(locationRule);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetLocationByCampaignAndLocationRuleId),
|
||||||
|
new { campaignId = campaignId, locationRuleId = locationRule.Id }, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("api/v1/campaigns/{campaignId:int}/locations/{userLocationRuleId:int}")]
|
||||||
|
public async Task<IActionResult> DeleteLocationById(int campaignId, int userLocationRuleId)
|
||||||
|
{
|
||||||
|
if (campaignId < 1 || userLocationRuleId < 1)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var locationToDelete = _context.Rules
|
||||||
|
.OfType<UserLocationRule>()
|
||||||
|
.SingleOrDefault(c => c.CampaignId == campaignId && c.Id == userLocationRuleId);
|
||||||
|
|
||||||
|
if (locationToDelete is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Rules.Remove(locationToDelete);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private List<UserLocationRuleDTO> MapUserLocationRuleModelListToDtoList(List<UserLocationRule> userLocationRuleList)
|
||||||
|
{
|
||||||
|
var userLocationRuleDtoList = new List<UserLocationRuleDTO>();
|
||||||
|
|
||||||
|
userLocationRuleList.ForEach(userLocationRule => userLocationRuleDtoList
|
||||||
|
.Add(MapUserLocationRuleModelToDto(userLocationRule)));
|
||||||
|
|
||||||
|
return userLocationRuleDtoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserLocationRuleDTO MapUserLocationRuleModelToDto(UserLocationRule userLocationRule)
|
||||||
|
{
|
||||||
|
return new UserLocationRuleDTO
|
||||||
|
{
|
||||||
|
Id = userLocationRule.Id,
|
||||||
|
Description = userLocationRule.Description,
|
||||||
|
LocationId = userLocationRule.LocationId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserLocationRule MapUserLocationRuleDtoToModel(UserLocationRuleDTO userLocationRuleDto)
|
||||||
|
{
|
||||||
|
return new UserLocationRule
|
||||||
|
{
|
||||||
|
Id = userLocationRuleDto.Id,
|
||||||
|
Description = userLocationRuleDto.Description,
|
||||||
|
LocationId = userLocationRuleDto.LocationId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
src/Services/Marketing/Marketing.API/Dockerfile
Normal file
6
src/Services/Marketing/Marketing.API/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FROM microsoft/aspnetcore:1.1.2
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "Marketing.API.dll"]
|
17
src/Services/Marketing/Marketing.API/Dto/CampaignDTO.cs
Normal file
17
src/Services/Marketing/Marketing.API/Dto/CampaignDTO.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Dto
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class CampaignDTO
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public DateTime From { get; set; }
|
||||||
|
|
||||||
|
public DateTime To { get; set; }
|
||||||
|
|
||||||
|
public string Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Dto
|
||||||
|
{
|
||||||
|
public class UserLocationRuleDTO
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int LocationId { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.ActionResults
|
||||||
|
{
|
||||||
|
using AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
public class InternalServerErrorObjectResult : ObjectResult
|
||||||
|
{
|
||||||
|
public InternalServerErrorObjectResult(object error)
|
||||||
|
: base(error)
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Exceptions
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception type for app exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class MarketingDomainException : Exception
|
||||||
|
{
|
||||||
|
public MarketingDomainException()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public MarketingDomainException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public MarketingDomainException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
using AspNetCore.Mvc;
|
||||||
|
using global::Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.ActionResults;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly IHostingEnvironment env;
|
||||||
|
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||||
|
|
||||||
|
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
this.env = env;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
logger.LogError(new EventId(context.Exception.HResult),
|
||||||
|
context.Exception,
|
||||||
|
context.Exception.Message);
|
||||||
|
|
||||||
|
if (context.Exception.GetType() == typeof(MarketingDomainException))
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { context.Exception.Message }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
//It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
|
context.Result = new BadRequestObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { "An error occur.Try it again." }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
json.DeveloperMessage = context.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
// It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
|
}
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JsonErrorResponse
|
||||||
|
{
|
||||||
|
public string[] Messages { get; set; }
|
||||||
|
|
||||||
|
public object DeveloperMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure
|
||||||
|
{
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Model;
|
||||||
|
|
||||||
|
public class MarketingContext : DbContext
|
||||||
|
{
|
||||||
|
public MarketingContext(DbContextOptions<MarketingContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<Campaign> Campaigns { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Rule> Rules { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Entity<Campaign>(ConfigureCampaigns);
|
||||||
|
builder.Entity<Rule>(ConfigureRules);
|
||||||
|
builder.Entity<UserLocationRule>(ConfigureUserLocationRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureCampaigns(EntityTypeBuilder<Campaign> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Campaign");
|
||||||
|
|
||||||
|
builder.HasKey(m => m.Id);
|
||||||
|
|
||||||
|
builder.Property(m => m.Id)
|
||||||
|
.ForSqlServerUseSequenceHiLo("campaign_hilo")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(m => m.Description)
|
||||||
|
.HasColumnName("Description")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(m => m.From)
|
||||||
|
.HasColumnName("From")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(m => m.To)
|
||||||
|
.HasColumnName("To")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(m => m.Description)
|
||||||
|
.HasColumnName("Description")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasMany(m => m.Rules)
|
||||||
|
.WithOne(r => r.Campaign)
|
||||||
|
.HasForeignKey(r => r.CampaignId)
|
||||||
|
.IsRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureRules(EntityTypeBuilder<Rule> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("Rule");
|
||||||
|
|
||||||
|
builder.HasKey(r => r.Id);
|
||||||
|
|
||||||
|
builder.Property(r => r.Id)
|
||||||
|
.ForSqlServerUseSequenceHiLo("rule_hilo")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasDiscriminator<int>("RuleTypeId")
|
||||||
|
.HasValue<UserProfileRule>((int)RuleTypeEnum.UserProfileRule)
|
||||||
|
.HasValue<PurchaseHistoryRule>((int)RuleTypeEnum.PurchaseHistoryRule)
|
||||||
|
.HasValue<UserLocationRule>((int)RuleTypeEnum.UserLocationRule);
|
||||||
|
|
||||||
|
builder.Property(r => r.Description)
|
||||||
|
.HasColumnName("Description")
|
||||||
|
.IsRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureUserLocationRules(EntityTypeBuilder<UserLocationRule> builder)
|
||||||
|
{
|
||||||
|
builder.Property(r => r.LocationId)
|
||||||
|
.HasColumnName("LocationId")
|
||||||
|
.IsRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Model;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class MarketingContextSeed
|
||||||
|
{
|
||||||
|
public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, int? retry = 0)
|
||||||
|
{
|
||||||
|
var context = (MarketingContext)applicationBuilder
|
||||||
|
.ApplicationServices.GetService(typeof(MarketingContext));
|
||||||
|
|
||||||
|
context.Database.Migrate();
|
||||||
|
|
||||||
|
if (!context.Campaigns.Any())
|
||||||
|
{
|
||||||
|
context.Campaigns.AddRange(
|
||||||
|
GetPreconfiguredMarketings());
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Campaign> GetPreconfiguredMarketings()
|
||||||
|
{
|
||||||
|
return new List<Campaign>
|
||||||
|
{
|
||||||
|
new Campaign
|
||||||
|
{
|
||||||
|
Description = "Campaign1",
|
||||||
|
From = DateTime.Now,
|
||||||
|
To = DateTime.Now.AddDays(7),
|
||||||
|
Url = "http://CampaignUrl.test/12f09ed3cef54187123f500ad",
|
||||||
|
Rules = new List<Rule>
|
||||||
|
{
|
||||||
|
new UserLocationRule
|
||||||
|
{
|
||||||
|
Description = "UserLocationRule1",
|
||||||
|
LocationId = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Campaign
|
||||||
|
{
|
||||||
|
Description = "Campaign2",
|
||||||
|
From = DateTime.Now.AddDays(7),
|
||||||
|
To = DateTime.Now.AddDays(14),
|
||||||
|
Url = "http://CampaignUrl.test/02a59eda65f241871239000ff",
|
||||||
|
Rules = new List<Rule>
|
||||||
|
{
|
||||||
|
new UserLocationRule
|
||||||
|
{
|
||||||
|
Description = "UserLocationRule2",
|
||||||
|
LocationId = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.MarketingMigrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(MarketingContext))]
|
||||||
|
[Migration("20170602122539_Initial")]
|
||||||
|
partial class Initial
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.2")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.campaign_hilo", "'campaign_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.rule_hilo", "'rule_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Campaign", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "campaign_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<DateTime>("From")
|
||||||
|
.HasColumnName("From");
|
||||||
|
|
||||||
|
b.Property<DateTime>("To")
|
||||||
|
.HasColumnName("To");
|
||||||
|
|
||||||
|
b.Property<string>("Url");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Campaign");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "rule_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<int>("CampaignId");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<int>("RuleTypeId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CampaignId");
|
||||||
|
|
||||||
|
b.ToTable("Rule");
|
||||||
|
|
||||||
|
b.HasDiscriminator<int>("RuleTypeId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.PurchaseHistoryRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
|
||||||
|
b.ToTable("PurchaseHistoryRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.UserLocationRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
b.Property<int>("LocationId")
|
||||||
|
.HasColumnName("LocationId");
|
||||||
|
|
||||||
|
b.ToTable("UserLocationRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.UserProfileRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
|
||||||
|
b.ToTable("UserProfileRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Campaign")
|
||||||
|
.WithMany("Rules")
|
||||||
|
.HasForeignKey("CampaignId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.MarketingMigrations
|
||||||
|
{
|
||||||
|
public partial class Initial : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateSequence(
|
||||||
|
name: "campaign_hilo",
|
||||||
|
incrementBy: 10);
|
||||||
|
|
||||||
|
migrationBuilder.CreateSequence(
|
||||||
|
name: "rule_hilo",
|
||||||
|
incrementBy: 10);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Campaign",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false),
|
||||||
|
Description = table.Column<string>(nullable: false),
|
||||||
|
From = table.Column<DateTime>(nullable: false),
|
||||||
|
To = table.Column<DateTime>(nullable: false),
|
||||||
|
Url = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Campaign", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Rule",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false),
|
||||||
|
CampaignId = table.Column<int>(nullable: false),
|
||||||
|
Description = table.Column<string>(nullable: false),
|
||||||
|
RuleTypeId = table.Column<int>(nullable: false),
|
||||||
|
LocationId = table.Column<int>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Rule", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Rule_Campaign_CampaignId",
|
||||||
|
column: x => x.CampaignId,
|
||||||
|
principalTable: "Campaign",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Rule_CampaignId",
|
||||||
|
table: "Rule",
|
||||||
|
column: "CampaignId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Rule");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Campaign");
|
||||||
|
|
||||||
|
migrationBuilder.DropSequence(
|
||||||
|
name: "campaign_hilo");
|
||||||
|
|
||||||
|
migrationBuilder.DropSequence(
|
||||||
|
name: "rule_hilo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.MarketingMigrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(MarketingContext))]
|
||||||
|
partial class MarketingContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.2")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.campaign_hilo", "'campaign_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.rule_hilo", "'rule_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Campaign", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "campaign_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<DateTime>("From")
|
||||||
|
.HasColumnName("From");
|
||||||
|
|
||||||
|
b.Property<DateTime>("To")
|
||||||
|
.HasColumnName("To");
|
||||||
|
|
||||||
|
b.Property<string>("Url");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Campaign");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "rule_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<int>("CampaignId");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("Description");
|
||||||
|
|
||||||
|
b.Property<int>("RuleTypeId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CampaignId");
|
||||||
|
|
||||||
|
b.ToTable("Rule");
|
||||||
|
|
||||||
|
b.HasDiscriminator<int>("RuleTypeId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.PurchaseHistoryRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
|
||||||
|
b.ToTable("PurchaseHistoryRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.UserLocationRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
b.Property<int>("LocationId")
|
||||||
|
.HasColumnName("LocationId");
|
||||||
|
|
||||||
|
b.ToTable("UserLocationRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.UserProfileRule", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule");
|
||||||
|
|
||||||
|
|
||||||
|
b.ToTable("UserProfileRule");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Rule", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Marketing.API.Model.Campaign")
|
||||||
|
.WithMany("Rules")
|
||||||
|
.HasForeignKey("CampaignId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
src/Services/Marketing/Marketing.API/Marketing.API.csproj
Normal file
50
src/Services/Marketing/Marketing.API/Marketing.API.csproj
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||||
|
<RuntimeFrameworkVersion>1.1.2</RuntimeFrameworkVersion>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
|
<RootNamespace>Microsoft.eShopOnContainers.Services.Marketing.API</RootNamespace>
|
||||||
|
<PackageTargetFallback>portable-net45+win8</PackageTargetFallback>
|
||||||
|
<UserSecretsId>aspnet-Marketing.API-20161122013619</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Infrastructure\MarketingMigrations\" />
|
||||||
|
<Folder Include="IntegrationEvents\EventHandling\" />
|
||||||
|
<Folder Include="IntegrationEvents\Events\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API
|
||||||
|
{
|
||||||
|
public class MarketingSettings
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
}
|
||||||
|
}
|
26
src/Services/Marketing/Marketing.API/Model/Campaign.cs
Normal file
26
src/Services/Marketing/Marketing.API/Model/Campaign.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class Campaign
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public DateTime From { get; set; }
|
||||||
|
|
||||||
|
public DateTime To { get; set; }
|
||||||
|
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
|
public List<Rule> Rules { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Campaign()
|
||||||
|
{
|
||||||
|
Rules = new List<Rule>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/Services/Marketing/Marketing.API/Model/Rule.cs
Normal file
33
src/Services/Marketing/Marketing.API/Model/Rule.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model
|
||||||
|
{
|
||||||
|
public abstract class Rule
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int CampaignId { get; set; }
|
||||||
|
|
||||||
|
public Campaign Campaign { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public abstract int RuleTypeId { get;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class UserProfileRule : Rule
|
||||||
|
{
|
||||||
|
public override int RuleTypeId => (int)RuleTypeEnum.UserProfileRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PurchaseHistoryRule : Rule
|
||||||
|
{
|
||||||
|
public override int RuleTypeId => (int)RuleTypeEnum.PurchaseHistoryRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserLocationRule : Rule
|
||||||
|
{
|
||||||
|
public override int RuleTypeId => (int)RuleTypeEnum.UserLocationRule;
|
||||||
|
|
||||||
|
public int LocationId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
20
src/Services/Marketing/Marketing.API/Model/RuleTypeEnum.cs
Normal file
20
src/Services/Marketing/Marketing.API/Model/RuleTypeEnum.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model
|
||||||
|
{
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Exceptions;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public enum RuleTypeEnum { UserProfileRule = 1, PurchaseHistoryRule = 2, UserLocationRule = 3 }
|
||||||
|
|
||||||
|
public static class RuleType
|
||||||
|
{
|
||||||
|
public static RuleTypeEnum From(int id)
|
||||||
|
{
|
||||||
|
if (!Enum.IsDefined(typeof(RuleTypeEnum), id))
|
||||||
|
{
|
||||||
|
throw new MarketingDomainException($"Invalid value for RuleType, RuleTypeId: {id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (RuleTypeEnum)id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/Services/Marketing/Marketing.API/Program.cs
Normal file
20
src/Services/Marketing/Marketing.API/Program.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API
|
||||||
|
{
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:5110",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Marketing.API": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:52059"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
src/Services/Marketing/Marketing.API/Startup.cs
Normal file
119
src/Services/Marketing/Marketing.API/Startup.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Marketing.API
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Reflection;
|
||||||
|
using System;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filters;
|
||||||
|
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IHostingEnvironment env)
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(env.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
Configuration = builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfigurationRoot Configuration { get; }
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
// Add framework services.
|
||||||
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
}).AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
|
services.AddDbContext<MarketingContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(Configuration["ConnectionString"],
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Changing default behavior when client evaluation occurs to throw.
|
||||||
|
// Default in EF Core would be to log a warning when client evaluation is performed.
|
||||||
|
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
|
||||||
|
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add framework services.
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
||||||
|
{
|
||||||
|
Title = "Marketing HTTP API",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "The Marketing Service HTTP API",
|
||||||
|
TermsOfService = "Terms Of Service"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
|
loggerFactory.AddDebug();
|
||||||
|
|
||||||
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
|
ConfigureAuth(app);
|
||||||
|
|
||||||
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
|
app.UseSwagger()
|
||||||
|
.UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
|
||||||
|
});
|
||||||
|
|
||||||
|
MarketingContextSeed.SeedAsync(app, loggerFactory)
|
||||||
|
.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
|
||||||
|
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
|
||||||
|
{
|
||||||
|
Authority = identityUrl.ToString(),
|
||||||
|
ApiName = "marketing",
|
||||||
|
RequireHttpsMetadata = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/Services/Marketing/Marketing.API/appsettings.json
Normal file
10
src/Services/Marketing/Marketing.API/appsettings.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionString": "127.0.0.1",
|
||||||
|
"IdentityUrl": "http://localhost:5105"
|
||||||
|
}
|
@ -20,6 +20,9 @@
|
|||||||
<Content Include="Services\Catalog\settings.json">
|
<Content Include="Services\Catalog\settings.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Services\Marketing\appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Services\Ordering\settings.json">
|
<Content Include="Services\Ordering\settings.json">
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@ -28,6 +31,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\src\Services\Basket\Basket.API\Basket.API.csproj" />
|
<ProjectReference Include="..\..\..\src\Services\Basket\Basket.API\Basket.API.csproj" />
|
||||||
<ProjectReference Include="..\..\..\src\Services\Catalog\Catalog.API\Catalog.API.csproj" />
|
<ProjectReference Include="..\..\..\src\Services\Catalog\Catalog.API\Catalog.API.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\src\Services\Marketing\Marketing.API\Marketing.API.csproj" />
|
||||||
<ProjectReference Include="..\..\..\src\Services\Ordering\Ordering.API\Ordering.API.csproj" />
|
<ProjectReference Include="..\..\..\src\Services\Ordering\Ordering.API\Ordering.API.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
public class CampaignScenarioBase : MarketingScenarioBase
|
||||||
|
{
|
||||||
|
public static class Get
|
||||||
|
{
|
||||||
|
public static string Campaigns = CampaignsUrlBase;
|
||||||
|
|
||||||
|
public static string CampaignBy(int id)
|
||||||
|
=> $"{CampaignsUrlBase}/{id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Post
|
||||||
|
{
|
||||||
|
public static string AddNewCampaign = CampaignsUrlBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Put
|
||||||
|
{
|
||||||
|
public static string CampaignBy(int id)
|
||||||
|
=> $"{CampaignsUrlBase}/{id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Delete
|
||||||
|
{
|
||||||
|
public static string CampaignBy(int id)
|
||||||
|
=> $"{CampaignsUrlBase}/{id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Dto;
|
||||||
|
|
||||||
|
public class CampaignScenarios
|
||||||
|
: CampaignScenarioBase
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Get_get_all_campaigns_and_response_ok_status_code()
|
||||||
|
{
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.GetAsync(Get.Campaigns);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Get_get_campaign_by_id_and_response_ok_status_code()
|
||||||
|
{
|
||||||
|
var campaignId = 1;
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.GetAsync(Get.CampaignBy(campaignId));
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Get_get_campaign_by_id_and_response_not_found_status_code()
|
||||||
|
{
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.GetAsync(Get.CampaignBy(int.MaxValue));
|
||||||
|
|
||||||
|
Assert.True(response.StatusCode == HttpStatusCode.NotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Post_add_new_campaign_and_response_ok_status_code()
|
||||||
|
{
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var fakeCampaignDto = GetFakeCampaignDto();
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.PostAsync(Post.AddNewCampaign, content);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Delete_delete_campaign_and_response_not_content_status_code()
|
||||||
|
{
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var fakeCampaignDto = GetFakeCampaignDto();
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
//add campaign
|
||||||
|
var campaignResponse = await server.CreateClient()
|
||||||
|
.PostAsync(Post.AddNewCampaign, content);
|
||||||
|
|
||||||
|
if (int.TryParse(campaignResponse.Headers.Location.Segments[4], out int id))
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.DeleteAsync(Delete.CampaignBy(id));
|
||||||
|
|
||||||
|
Assert.True(response.StatusCode == HttpStatusCode.NoContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
campaignResponse.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Put_update_campaign_and_response_not_content_status_code()
|
||||||
|
{
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var fakeCampaignDto = GetFakeCampaignDto();
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
//add campaign
|
||||||
|
var campaignResponse = await server.CreateClient()
|
||||||
|
.PostAsync(Post.AddNewCampaign, content);
|
||||||
|
|
||||||
|
if (int.TryParse(campaignResponse.Headers.Location.Segments[4], out int id))
|
||||||
|
{
|
||||||
|
fakeCampaignDto.Description = "FakeCampaignUpdatedDescription";
|
||||||
|
content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.PutAsync(Put.CampaignBy(id), content);
|
||||||
|
|
||||||
|
Assert.True(response.StatusCode == HttpStatusCode.Created);
|
||||||
|
}
|
||||||
|
|
||||||
|
campaignResponse.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CampaignDTO GetFakeCampaignDto()
|
||||||
|
{
|
||||||
|
return new CampaignDTO()
|
||||||
|
{
|
||||||
|
Description = "FakeCampaignDescription",
|
||||||
|
From = DateTime.Now,
|
||||||
|
To = DateTime.Now.AddDays(7),
|
||||||
|
Url = "http://CampaignUrl.test/fdaf91ad0cef5419719f50198",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
public class MarketingScenarioBase
|
||||||
|
{
|
||||||
|
public static string CampaignsUrlBase => "api/v1/campaigns";
|
||||||
|
|
||||||
|
public TestServer CreateServer()
|
||||||
|
{
|
||||||
|
var webHostBuilder = new WebHostBuilder();
|
||||||
|
webHostBuilder.UseContentRoot(Directory.GetCurrentDirectory() + "\\Services\\Marketing");
|
||||||
|
webHostBuilder.UseStartup<MarketingTestsStartup>();
|
||||||
|
|
||||||
|
return new TestServer(webHostBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using IntegrationTests.Middleware;
|
||||||
|
|
||||||
|
public class MarketingTestsStartup : Startup
|
||||||
|
{
|
||||||
|
public MarketingTestsStartup(IHostingEnvironment env) : base(env)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ConfigureAuth(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
app.UseMiddleware<AutoAuthorizeMiddleware>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.ConfigureAuth(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Marketing.API.Dto;
|
||||||
|
|
||||||
|
public class UserLocationRoleScenarios
|
||||||
|
: UserLocationRoleScenariosBase
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Get_get_all_user_location_rules_by_campaignId_and_response_ok_status_code()
|
||||||
|
{
|
||||||
|
var campaignId = 1;
|
||||||
|
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.GetAsync(Get.UserLocationRulesByCampaignId(campaignId));
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Post_add_new_user_location_rule_and_response_ok_status_code()
|
||||||
|
{
|
||||||
|
var campaignId = 1;
|
||||||
|
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var fakeCampaignDto = GetFakeUserLocationRuleDto();
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.PostAsync(Post.AddNewuserLocationRule(campaignId), content);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Delete_delete_user_location_role_and_response_not_content_status_code()
|
||||||
|
{
|
||||||
|
var campaignId = 1;
|
||||||
|
|
||||||
|
using (var server = CreateServer())
|
||||||
|
{
|
||||||
|
var fakeCampaignDto = GetFakeUserLocationRuleDto();
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(fakeCampaignDto), Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
//add user location role
|
||||||
|
var campaignResponse = await server.CreateClient()
|
||||||
|
.PostAsync(Post.AddNewuserLocationRule(campaignId), content);
|
||||||
|
|
||||||
|
if (int.TryParse(campaignResponse.Headers.Location.Segments[6], out int userLocationRuleId))
|
||||||
|
{
|
||||||
|
var response = await server.CreateClient()
|
||||||
|
.DeleteAsync(Delete.UserLocationRoleBy(campaignId, userLocationRuleId));
|
||||||
|
|
||||||
|
Assert.True(response.StatusCode == HttpStatusCode.NoContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
campaignResponse.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UserLocationRuleDTO GetFakeUserLocationRuleDto()
|
||||||
|
{
|
||||||
|
return new UserLocationRuleDTO
|
||||||
|
{
|
||||||
|
LocationId = 20,
|
||||||
|
Description = "FakeUserLocationRuleDescription"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
namespace IntegrationTests.Services.Marketing
|
||||||
|
{
|
||||||
|
public class UserLocationRoleScenariosBase : MarketingScenarioBase
|
||||||
|
{
|
||||||
|
private const string EndpointLocationName = "locations";
|
||||||
|
public static class Get
|
||||||
|
{
|
||||||
|
public static string UserLocationRulesByCampaignId(int campaignId)
|
||||||
|
=> GetUserLocationRolesUrlBase(campaignId);
|
||||||
|
|
||||||
|
public static string UserLocationRuleByCampaignAndUserLocationRuleId(int campaignId,
|
||||||
|
int userLocationRuleId)
|
||||||
|
=> $"{GetUserLocationRolesUrlBase(campaignId)}/{userLocationRuleId}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Post
|
||||||
|
{
|
||||||
|
public static string AddNewuserLocationRule(int campaignId)
|
||||||
|
=> GetUserLocationRolesUrlBase(campaignId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Put
|
||||||
|
{
|
||||||
|
public static string UserLocationRoleBy(int campaignId,
|
||||||
|
int userLocationRuleId)
|
||||||
|
=> $"{GetUserLocationRolesUrlBase(campaignId)}/{userLocationRuleId}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Delete
|
||||||
|
{
|
||||||
|
public static string UserLocationRoleBy(int campaignId,
|
||||||
|
int userLocationRuleId)
|
||||||
|
=> $"{GetUserLocationRolesUrlBase(campaignId)}/{userLocationRuleId}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static string GetUserLocationRolesUrlBase(int campaignId)
|
||||||
|
=> $"{CampaignsUrlBase}/{campaignId}/{EndpointLocationName}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word",
|
||||||
|
"IdentityUrl": "http://localhost:5105",
|
||||||
|
"isTest": "true"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user