# Conflicts: # eShopOnContainers-ServicesAndWebApps.slnpull/809/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" | |||
} |