# Conflicts: # eShopOnContainers-ServicesAndWebApps.slnpull/223/head
@ -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 | |||||
}; | |||||
} | |||||
} | |||||
} |
@ -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"] |
@ -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); | |||||
}); | |||||
} | |||||
} | |||||
} |
@ -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; } | |||||
} | |||||
} |
@ -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>(); | |||||
} | |||||
} | |||||
} |
@ -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; } | |||||
} | |||||
} |
@ -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; | |||||
} | |||||
} | |||||
} |
@ -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" | |||||
} | |||||
} | |||||
} |
@ -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" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,10 @@ | |||||
{ | |||||
"Logging": { | |||||
"IncludeScopes": false, | |||||
"LogLevel": { | |||||
"Default": "Warning" | |||||
} | |||||
}, | |||||
"ConnectionString": "127.0.0.1", | |||||
"IdentityUrl": "http://localhost:5105" | |||||
} |
@ -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" | |||||
} |