@ -1,118 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands | |||
{ | |||
using Domain.Repositories; | |||
using MediatR; | |||
using System.Linq; | |||
using System; | |||
using System.Threading.Tasks; | |||
using Domain; | |||
public class NewOrderRequestHandler | |||
: IAsyncRequestHandler<NewOrderRequest, bool> | |||
{ | |||
private readonly IBuyerRepository _buyerRepository; | |||
private readonly IOrderRepository _orderRepository; | |||
public NewOrderRequestHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository) | |||
{ | |||
if (buyerRepository == null) | |||
{ | |||
throw new ArgumentNullException(nameof(buyerRepository)); | |||
} | |||
if (orderRepository == null) | |||
{ | |||
throw new ArgumentNullException(nameof(orderRepository)); | |||
} | |||
_buyerRepository = buyerRepository; | |||
_orderRepository = orderRepository; | |||
} | |||
public async Task<bool> Handle(NewOrderRequest message) | |||
{ | |||
//find buyer/payment or add a new one buyer/payment | |||
var buyer = await _buyerRepository.FindAsync(message.Buyer); | |||
if (buyer == null) | |||
{ | |||
buyer = CreateBuyer(message); | |||
} | |||
var payment = GetExistingPaymentOrAddANewOne(buyer, message); | |||
await _buyerRepository.UnitOfWork | |||
.SaveChangesAsync(); | |||
//create order for buyer and payment method | |||
var order = CreateOrder(buyer.Id, payment.Id, 0); | |||
order.SetAddress( new Address() | |||
{ | |||
City = message.City, | |||
State = message.State, | |||
Street = message.Street, | |||
ZipCode = message.ZipCode | |||
}); | |||
foreach (var item in message.OrderItems) | |||
{ | |||
order.AddOrderItem(item); | |||
} | |||
_orderRepository.Add(order); | |||
var result = await _orderRepository.UnitOfWork | |||
.SaveChangesAsync(); | |||
return result > 0; | |||
} | |||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderRequest message) | |||
{ | |||
Payment payment = PaymentAlreadyExist(buyer, message); | |||
if (payment == null) | |||
{ | |||
payment = CreatePayment(message); | |||
buyer.Payments.Add(payment); | |||
} | |||
return payment; | |||
} | |||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderRequest message) | |||
{ | |||
return buyer.Payments | |||
.SingleOrDefault(p => | |||
{ | |||
return p.CardHolderName == message.CardHolderName | |||
&& | |||
p.CardNumber == message.CardNumber | |||
&& | |||
p.Expiration == message.CardExpiration | |||
&& | |||
p.SecurityNumber == message.CardSecurityNumber; | |||
}); | |||
} | |||
Buyer CreateBuyer(NewOrderRequest message) | |||
{ | |||
return _buyerRepository.Add( | |||
new Buyer(message.Buyer)); | |||
} | |||
Order CreateOrder(int buyerId, int paymentId, int addressId) | |||
{ | |||
return new Order(buyerId, paymentId); | |||
} | |||
Payment CreatePayment(NewOrderRequest message) | |||
{ | |||
return new Payment(message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration, message.CardTypeId); | |||
} | |||
} | |||
} |
@ -1,48 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands | |||
{ | |||
using System; | |||
using MediatR; | |||
using Domain; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
public class NewOrderRequest | |||
:IAsyncRequest<bool> | |||
{ | |||
private readonly List<OrderItem> _orderItems; | |||
public string City { get; set; } | |||
public string Street { get; set; } | |||
public string State { get; set; } | |||
public string Country { get; set; } | |||
public string ZipCode { get; set; } | |||
public string CardNumber { get; set; } | |||
public string CardHolderName { get; set; } | |||
public DateTime CardExpiration { get; set; } | |||
public string CardSecurityNumber { get; set; } | |||
public int CardTypeId { get; set; } | |||
public string Buyer { get; set; } | |||
public IEnumerable<OrderItem> OrderItems => _orderItems; | |||
public void AddOrderItem(OrderItem item) | |||
{ | |||
_orderItems.Add(item); | |||
} | |||
public NewOrderRequest() | |||
{ | |||
_orderItems = new List<OrderItem>(); | |||
} | |||
} | |||
} |
@ -1,34 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Decorators | |||
{ | |||
using Extensions.Logging; | |||
using MediatR; | |||
using System.Threading.Tasks; | |||
public class LogDecorator<TRequest, TResponse> | |||
: IAsyncRequestHandler<TRequest, TResponse> | |||
where TRequest : IAsyncRequest<TResponse> | |||
{ | |||
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner; | |||
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger; | |||
public LogDecorator( | |||
IAsyncRequestHandler<TRequest, TResponse> inner, | |||
ILogger<LogDecorator<TRequest, TResponse>> logger) | |||
{ | |||
_inner = inner; | |||
_logger = logger; | |||
} | |||
public async Task<TResponse> Handle(TRequest message) | |||
{ | |||
_logger.LogInformation($"Executing command {_inner.GetType().FullName}"); | |||
var response = await _inner.Handle(message); | |||
_logger.LogInformation($"Succedded executed command {_inner.GetType().FullName}"); | |||
return response; | |||
} | |||
} | |||
} |
@ -1,19 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>4193caa3-a1c3-4818-a06f-a2d85fde77e7</ProjectGuid> | |||
<RootNamespace>Microsoft.eShopOnContainers.Services.Ordering.Application</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@ -1,19 +0,0 @@ | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
// General Information about an assembly is controlled through the following | |||
// set of attributes. Change these attribute values to modify the information | |||
// associated with an assembly. | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("")] | |||
[assembly: AssemblyProduct("Ordering.Application")] | |||
[assembly: AssemblyTrademark("")] | |||
// Setting ComVisible to false makes the types in this assembly not visible | |||
// to COM components. If you need to access a type in this assembly from | |||
// COM, set the ComVisible attribute to true on that type. | |||
[assembly: ComVisible(false)] | |||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||
[assembly: Guid("4193caa3-a1c3-4818-a06f-a2d85fde77e7")] |
@ -1,13 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries | |||
{ | |||
using System.Threading.Tasks; | |||
public interface IOrderQueries | |||
{ | |||
Task<dynamic> GetOrder(int id); | |||
Task<dynamic> GetOrders(); | |||
Task<dynamic> GetCardTypes(); | |||
} | |||
} |
@ -1,128 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries | |||
{ | |||
using Dapper; | |||
using Microsoft.Extensions.Configuration; | |||
using System.Data.SqlClient; | |||
using System.Threading.Tasks; | |||
using System; | |||
using System.Dynamic; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
public class OrderQueries | |||
: IOrderQueries | |||
{ | |||
private string _connectionString = string.Empty; | |||
public OrderQueries(IConfiguration configuration) | |||
{ | |||
_connectionString = configuration["ConnectionString"]; | |||
} | |||
public async Task<dynamic> GetOrder(int id) | |||
{ | |||
using (var connection = new SqlConnection(_connectionString)) | |||
{ | |||
connection.Open(); | |||
var result = await connection.QueryAsync<dynamic>( | |||
@"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status, | |||
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl, | |||
oa.Street as street, oa.City as city, oa.Country as country, oa.State as state, oa.ZipCode as zipcode | |||
FROM ordering.Orders o | |||
LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid | |||
LEFT JOIN ordering.orderstatus os on o.StatusId = os.Id | |||
LEFT JOIN ordering.address oa on o.ShippingAddressId = oa.Id | |||
WHERE o.Id=@id" | |||
, new { id } | |||
); | |||
if (result.AsList().Count == 0) | |||
throw new KeyNotFoundException(); | |||
return MapOrderItems(result); | |||
} | |||
} | |||
public async Task<dynamic> GetOrders() | |||
{ | |||
using (var connection = new SqlConnection(_connectionString)) | |||
{ | |||
connection.Open(); | |||
return await connection.QueryAsync<dynamic>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total | |||
FROM [ordering].[Orders] o | |||
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid | |||
LEFT JOIN[ordering].[orderstatus] os on o.StatusId = os.Id | |||
GROUP BY o.[Id], o.[OrderDate], os.[Name]"); | |||
} | |||
} | |||
public async Task<dynamic> GetCardTypes() | |||
{ | |||
using (var connection = new SqlConnection(_connectionString)) | |||
{ | |||
connection.Open(); | |||
return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.cardtypes"); | |||
} | |||
} | |||
private dynamic MapOrderItems(dynamic result) | |||
{ | |||
dynamic order = new ExpandoObject(); | |||
order.ordernumber = result[0].ordernumber; | |||
order.date = result[0].date; | |||
order.status = result[0].status; | |||
order.street = result[0].street; | |||
order.city = result[0].city; | |||
order.zipcode = result[0].zipcode; | |||
order.country = result[0].country; | |||
order.orderitems = new List<dynamic>(); | |||
order.total = 0; | |||
foreach (dynamic item in result) | |||
{ | |||
dynamic orderitem = new ExpandoObject(); | |||
orderitem.productname = item.productname; | |||
orderitem.units = item.units; | |||
orderitem.unitprice = item.unitprice; | |||
orderitem.pictureurl = item.pictureurl; | |||
order.total += item.units * item.unitprice; | |||
order.orderitems.Add(orderitem); | |||
} | |||
return order; | |||
} | |||
//TODO/CCE: try to use this method instead actual. | |||
//private object MapOrderItems(dynamic result) | |||
//{ | |||
// IEnumerable<dynamic> items = (result as System.Collections.IEnumerable).Cast<dynamic>(); | |||
// var order = new | |||
// { | |||
// ordernumber = result[0].ordernumbe, | |||
// date = result[0].date, | |||
// status = result[0].status, | |||
// street = result[0].street, | |||
// city = result[0].city, | |||
// zipcode = result[0].zipcode, | |||
// country = result[0].country, | |||
// total = items.Select(r => (int)r.units * (int)r.unitprice).Sum(), | |||
// orderItems = items.Select(r => new | |||
// { | |||
// productname = r.productname, | |||
// units = r.units, | |||
// unitprice = r.unitprice, | |||
// pictureurl = r.pictureurl | |||
// }) | |||
// }; | |||
// return order; | |||
//} | |||
} | |||
} |
@ -1,21 +0,0 @@ | |||
{ | |||
"version": "1.0.0-*", | |||
"dependencies": { | |||
"NETStandard.Library": "1.6.0", | |||
"MediatR": "2.1.0", | |||
"Dapper": "1.50.2", | |||
"System.Dynamic.Runtime": "4.0.11", | |||
"Microsoft.CSharp": "4.0.1", | |||
"Microsoft.Extensions.Configuration": "1.0.0", | |||
"System.Data.SqlClient": "4.1.0", | |||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0", | |||
"Ordering.Domain": "1.0.0-*" | |||
}, | |||
"frameworks": { | |||
"netstandard1.6": { | |||
"imports": "dnxcore50" | |||
} | |||
} | |||
} |
@ -0,0 +1,111 @@ | |||
rules: | |||
# https://github.com/sasstools/sass-lint/tree/master/docs/rules | |||
# 0 = disabled - 1 = warning - 2 = error | |||
# Extends | |||
extends-before-mixins: 1 | |||
extends-before-declarations: 2 | |||
placeholder-in-extend: 0 | |||
# Mixins | |||
mixins-before-declarations: 2 | |||
# Line Spacing | |||
one-declaration-per-line: 2 | |||
empty-line-between-blocks: 2 | |||
single-line-per-selector: 2 | |||
# Disallows | |||
# We disable some of that because we know that | |||
# if you use it is because is necessary | |||
no-attribute-selectors: 0 | |||
no-color-hex: 0 | |||
no-color-keywords: 2 | |||
no-color-literals: 0 | |||
no-combinators: 0 | |||
no-css-comments: 0 | |||
no-debug: 1 | |||
no-disallowed-properties: 0 | |||
no-duplicate-properties: 2 | |||
no-empty-rulesets: 1 | |||
no-extends: 0 | |||
no-ids: 2 | |||
no-important: 0 | |||
no-invalid-hex: 2 | |||
no-mergeable-selectors: 1 | |||
no-misspelled-properties: 2 | |||
no-qualifying-elements: 0 | |||
no-trailing-whitespace: 2 | |||
no-trailing-zero: 2 | |||
no-transition-all: 0 | |||
no-universal-selectors: 0 | |||
no-url-domains: 0 | |||
no-url-protocols: 0 | |||
no-vendor-prefixes: 2 | |||
no-warn: 2 | |||
property-units: 0 | |||
# Nesting | |||
declarations-before-nesting: 2 | |||
force-attribute-nesting: 0 | |||
force-element-nesting: 0 | |||
force-pseudo-nesting: 0 | |||
# Name Formats | |||
class-name-format: 0 | |||
function-name-format: 0 | |||
id-name-format: 0 | |||
mixin-name-format: 0 | |||
placeholder-name-format: | |||
- 1 | |||
- allow-leading-underscore: true | |||
- convention: hyphenatedlowercase | |||
variable-name-format: | |||
- 1 | |||
- allow-leading-underscore: true | |||
- convention: hyphenatedlowercase | |||
# Style Guide | |||
attribute-quotes: 2 | |||
# We know that always 1 level | |||
bem-depth: 0 | |||
border-zero: 2 | |||
brace-style: | |||
- 2 | |||
- style: 1tbs | |||
clean-import-paths: 2 | |||
empty-args: 2 | |||
hex-length: | |||
- 2 | |||
- style: long | |||
hex-notation: | |||
- 2 | |||
- style: uppercase | |||
indentation: | |||
- 2 | |||
- size: 4 | |||
leading-zero: 2 | |||
max-line-length: 0 | |||
max-file-line-count: 0 | |||
nesting-depth: 0 | |||
# alphabetically | |||
property-sort-order: 2 | |||
pseudo-element: 0 | |||
quotes: 2 | |||
shorthand-values: 0 | |||
url-quotes: 0 | |||
variable-for-property: 0 | |||
zero-unit: 2 | |||
# Inner Spacing | |||
space-after-comma: 2 | |||
space-before-colon: 2 | |||
space-after-colon: 2 | |||
space-before-brace: 2 | |||
space-before-bang: 2 | |||
space-after-bang: 2 | |||
space-between-parens: 2 | |||
space-around-operator: 2 | |||
# Final Items | |||
trailing-semicolon: 2 | |||
final-newline: 2 |
@ -0,0 +1,7 @@ | |||
<div class="esh-header"> | |||
<div class="container"> | |||
<a class="esh-header-back" routerLink="{{url}}"> | |||
<ng-content></ng-content> | |||
</a> | |||
</div> | |||
</div> |
@ -0,0 +1,21 @@ | |||
@import "../../../variables"; | |||
.esh-header { | |||
$header-height: 4rem; | |||
background-color: $color-brand; | |||
height: $header-height; | |||
&-back { | |||
color: rgba($color-foreground-brighter, .5); | |||
line-height: $header-height; | |||
text-transform: uppercase; | |||
text-decoration: none; | |||
transition: color $animation-speed-default; | |||
&:hover { | |||
color: $color-foreground-brighter; | |||
transition: color $animation-speed-default; | |||
} | |||
} | |||
} |
@ -0,0 +1,11 @@ | |||
import { Component, Input } from '@angular/core'; | |||
@Component({ | |||
selector: 'esh-header', | |||
templateUrl: './header.html', | |||
styleUrls: ['./header.scss'] | |||
}) | |||
export class Header { | |||
@Input() | |||
url: string; | |||
} |
@ -1,8 +1,35 @@ | |||
<button *ngIf="!authenticated" class="identity-login" (click)="login()">Login</button> | |||
<div *ngIf="authenticated" class="identity-user"> | |||
<div><span>{{userName}}</span></div><div style="float: right;top: 0;right: -15px;position: absolute;"><img src="../../../../images/arrow-down.png" class="identity-downArrow"></div> | |||
<div class="identity-userDropdown"> | |||
<div [routerLink]="['orders']">MY ORDERS<img src="../../../../images/my_orders.png"></div> | |||
<div (click)="logoutClicked($event)">LOG OUT<img src="../../../../images/logout.png"></div> | |||
</div> | |||
<div class="esh-identity"> | |||
<section class="esh-identity-section" | |||
*ngIf="!authenticated"> | |||
<div class="esh-identity-item" | |||
(click)="login()"> | |||
<div class="esh-identity-name esh-identity-name--upper">Login</div> | |||
</div> | |||
</section> | |||
<section class="esh-identity-section" | |||
*ngIf="authenticated"> | |||
<div class="esh-identity-name">{{userName}}</div> | |||
<img class="esh-identity-image" src="../../../../images/arrow-down.png"> | |||
</section> | |||
<section class="esh-identity-drop" | |||
*ngIf="authenticated"> | |||
<div class="esh-identity-item" | |||
[routerLink]="['orders']"> | |||
<div class="esh-identity-name esh-identity-name--upper">My orders</div> | |||
<img class="esh-identity-image" src="../../../../images/my_orders.png"> | |||
</div> | |||
<div class="esh-identity-item" | |||
(click)="logoutClicked($event)"> | |||
<div class="esh-identity-name esh-identity-name--upper">Log Out</div> | |||
<img class="esh-identity-image" src="../../../../images/logout.png"> | |||
</div> | |||
</section> | |||
</div> |
@ -1,63 +1,56 @@ | |||
.identity { | |||
&-user { | |||
position: absolute !important; | |||
top: 30px; | |||
right: 120px; | |||
cursor: pointer; | |||
@import "../../../variables"; | |||
&:hover .identity-userDropdown { | |||
display: block; | |||
} | |||
} | |||
.esh-identity { | |||
line-height: 3rem; | |||
position: relative; | |||
text-align: right; | |||
&-userDropdown { | |||
display: none; | |||
position: absolute; | |||
background-color: #FFFFFF; | |||
min-width: 160px; | |||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); | |||
right: -15px; | |||
z-index: 3; | |||
&-section { | |||
display: inline-block; | |||
width: 100%; | |||
} | |||
&:hover { | |||
display: block; | |||
} | |||
&-name { | |||
display: inline-block; | |||
& div { | |||
color: black; | |||
padding: 12px 16px; | |||
text-decoration: none; | |||
display: block; | |||
text-align: right; | |||
&--upper { | |||
text-transform: uppercase; | |||
} | |||
&:hover { | |||
color: #83d01b; | |||
} | |||
@media screen and (max-width: $media-screen-s) { | |||
font-size: $font-size-s; | |||
} | |||
} | |||
&-downArrow { | |||
height: 7px; | |||
width: 10px; | |||
&-image { | |||
display: inline-block; | |||
margin-left: 20px; | |||
} | |||
&:hover > identity.userDropdown { | |||
display: block; | |||
} | |||
&-drop { | |||
background: $color-background-brighter; | |||
height: 0; | |||
min-width: 14rem; | |||
right: 0; | |||
overflow: hidden; | |||
padding: .5rem; | |||
position: absolute; | |||
top: 2.5rem; | |||
transition: height $animation-speed-default; | |||
} | |||
&:hover &-drop { | |||
border: $border-light solid $color-foreground-bright; | |||
height: 7rem; | |||
transition: height $animation-speed-default; | |||
} | |||
&-login { | |||
border: 1px solid #00a69c; | |||
height: 36px !important; | |||
margin-right: 10px; | |||
margin-top: 10px; | |||
background-color: #fff; | |||
color: #00a69c; | |||
text-transform: uppercase; | |||
max-width: 140px; | |||
width: 140px; | |||
padding-top: 8px !important; | |||
&-item { | |||
cursor: pointer; | |||
transition: color $animation-speed-default; | |||
&:hover { | |||
color: $color-secondary-dark; | |||
transition: color $animation-speed-default; | |||
} | |||
} | |||
} |
@ -1,178 +0,0 @@ | |||
{ | |||
"rulesDirectory": [ | |||
"node_modules/codelyzer" | |||
], | |||
"rules": { | |||
"directive-selector-name": [ | |||
true, | |||
"camelCase" | |||
], | |||
"component-selector-name": [ | |||
true, | |||
"kebab-case" | |||
], | |||
"directive-selector-type": [ | |||
true, | |||
"attribute" | |||
], | |||
"component-selector-type": [ | |||
true, | |||
"element" | |||
], | |||
"directive-selector-prefix": [ | |||
true, | |||
"appd" | |||
], | |||
"component-selector-prefix": [ | |||
true, | |||
"appc" | |||
], | |||
"use-input-property-decorator": true, | |||
"use-output-property-decorator": true, | |||
"use-host-property-decorator": true, | |||
"no-attribute-parameter-decorator": true, | |||
"no-input-rename": true, | |||
"no-output-rename": true, | |||
"no-forward-ref": true, | |||
"use-life-cycle-interface": true, | |||
"use-pipe-transform-interface": true, | |||
"pipe-naming": [ | |||
true, | |||
"camelCase", | |||
"appf" | |||
], | |||
"component-class-suffix": true, | |||
"directive-class-suffix": true, | |||
"import-destructuring-spacing": true, | |||
"member-access": false, | |||
"member-ordering": [ | |||
true, | |||
"public-before-private", | |||
"static-before-instance", | |||
"variables-before-functions" | |||
], | |||
"no-any": false, | |||
"no-inferrable-types": false, | |||
"no-internal-module": true, | |||
"no-var-requires": false, | |||
"typedef": false, | |||
"typedef-whitespace": [ | |||
true, | |||
{ | |||
"call-signature": "nospace", | |||
"index-signature": "nospace", | |||
"parameter": "nospace", | |||
"property-declaration": "nospace", | |||
"variable-declaration": "nospace" | |||
}, | |||
{ | |||
"call-signature": "space", | |||
"index-signature": "space", | |||
"parameter": "space", | |||
"property-declaration": "space", | |||
"variable-declaration": "space" | |||
} | |||
], | |||
"ban": false, | |||
"curly": false, | |||
"forin": true, | |||
"label-position": true, | |||
"label-undefined": true, | |||
"no-arg": true, | |||
"no-bitwise": true, | |||
"no-conditional-assignment": true, | |||
"no-console": [ | |||
true, | |||
"debug", | |||
"info", | |||
"time", | |||
"timeEnd", | |||
"trace" | |||
], | |||
"no-construct": true, | |||
"no-debugger": true, | |||
"no-duplicate-key": true, | |||
"no-duplicate-variable": true, | |||
"no-empty": false, | |||
"no-eval": true, | |||
"no-null-keyword": true, | |||
"no-shadowed-variable": true, | |||
"no-string-literal": true, | |||
"no-switch-case-fall-through": true, | |||
"no-unreachable": true, | |||
"no-unused-expression": true, | |||
"no-unused-variable": false, | |||
"no-use-before-declare": true, | |||
"no-var-keyword": true, | |||
"radix": true, | |||
"switch-default": true, | |||
"triple-equals": [ | |||
true, | |||
"allow-null-check" | |||
], | |||
"use-strict": [ | |||
true, | |||
"check-module" | |||
], | |||
"eofline": true, | |||
"indent": [ | |||
true, | |||
"spaces" | |||
], | |||
"max-line-length": [ | |||
true, | |||
200 | |||
], | |||
"no-require-imports": false, | |||
"no-trailing-whitespace": true, | |||
"object-literal-sort-keys": false, | |||
"trailing-comma": [ | |||
true, | |||
{ | |||
"multiline": "never", | |||
"singleline": "never" | |||
} | |||
], | |||
"align": false, | |||
"class-name": true, | |||
"comment-format": [ | |||
true, | |||
"check-space" | |||
], | |||
"interface-name": false, | |||
"jsdoc-format": true, | |||
"no-consecutive-blank-lines": false, | |||
"no-constructor-vars": false, | |||
"one-line": [ | |||
true, | |||
"check-open-brace", | |||
"check-catch", | |||
"check-else", | |||
"check-finally", | |||
"check-whitespace" | |||
], | |||
"quotemark": [ | |||
true, | |||
"single", | |||
"avoid-escape" | |||
], | |||
"semicolon": [ | |||
true, | |||
"always" | |||
], | |||
"variable-name": [ | |||
true, | |||
"check-format", | |||
"allow-leading-underscore", | |||
"ban-keywords" | |||
], | |||
"whitespace": [ | |||
true, | |||
"check-branch", | |||
"check-decl", | |||
"check-operator", | |||
"check-separator", | |||
"check-type" | |||
] | |||
} | |||
} |
@ -0,0 +1,63 @@ | |||
| |||
//namespace FunctionalTests.Services.Basket | |||
//{ | |||
// using Microsoft.eShopOnContainers.Services.Basket.API; | |||
// using Microsoft.eShopOnContainers.Services.Basket.API.Model; | |||
// using Microsoft.Extensions.Logging; | |||
// using Microsoft.Extensions.Options; | |||
// using System.Collections.Generic; | |||
// using System.Threading.Tasks; | |||
// using Xunit; | |||
// public class RedisBasketRepositoryTests | |||
// { | |||
// [Fact] | |||
// public async Task UpdateBasket_return_and_add_basket() | |||
// { | |||
// var redisBasketRepository = BuildBasketRepository(); | |||
// var basket = await redisBasketRepository.UpdateBasket(new CustomerBasket("customerId") | |||
// { | |||
// BuyerId = "buyerId", | |||
// Items = BuildBasketItems() | |||
// }); | |||
// Assert.NotNull(basket); | |||
// Assert.Equal(1, basket.Items.Count); | |||
// } | |||
// [Fact] | |||
// public async Task GetBasket_return_existing_basket() | |||
// { | |||
// } | |||
// RedisBasketRepository BuildBasketRepository() | |||
// { | |||
// var loggerFactory = new LoggerFactory(); | |||
// var options = Options.Create<BasketSettings>(new BasketSettings() | |||
// { | |||
// ConnectionString = "127.0.0.1" | |||
// }); | |||
// return new RedisBasketRepository(options, loggerFactory); | |||
// } | |||
// List<BasketItem> BuildBasketItems() | |||
// { | |||
// return new List<BasketItem>() | |||
// { | |||
// new BasketItem() | |||
// { | |||
// Id = "basketId", | |||
// PictureUrl = "pictureurl", | |||
// ProductId = "productId", | |||
// ProductName = "productName", | |||
// Quantity = 1, | |||
// UnitPrice = 1 | |||
// } | |||
// }; | |||
// } | |||
// } | |||
//} |
@ -1,136 +0,0 @@ | |||
using System; | |||
using Xunit; | |||
using System.Threading.Tasks; | |||
using Moq; | |||
using MediatR; | |||
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; | |||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands; | |||
using Microsoft.AspNetCore.Mvc; | |||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; | |||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Queries; | |||
using System.Collections.Generic; | |||
namespace UnitTest.Ordering.Controllers | |||
{ | |||
public class OrderControllerTest | |||
{ | |||
private readonly Mock<IMediator> _mediatorMock; | |||
private readonly Mock<IIdentityService> _identityMock; | |||
private readonly Mock<IOrderQueries> _queriesMock; | |||
private readonly string _userIdentity; | |||
public OrderControllerTest() | |||
{ | |||
//Mocks; | |||
_mediatorMock = new Mock<IMediator>(); | |||
_identityMock = new Mock<IIdentityService>(); | |||
_queriesMock = new Mock<IOrderQueries>(); | |||
_userIdentity = Guid.NewGuid().ToString(); | |||
} | |||
[Fact] | |||
public async Task AddOrder_ReturnsBadRequestResult_WhenPersitenceOperationFails() | |||
{ | |||
// Arrange | |||
var orderRequest = new object() as IAsyncRequest<bool>; | |||
_mediatorMock.Setup(mediator => mediator.SendAsync(OrderFakeNotExpired())) | |||
.Returns(Task.FromResult(false)); | |||
_identityMock.Setup(identity => identity.GetUserIdentity()) | |||
.Returns(Guid.NewGuid().ToString()); | |||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||
// Act | |||
var badRequestResult = await controller.AddOrder(OrderFakeNotExpired()); | |||
// Assert | |||
Assert.IsType<BadRequestResult>(badRequestResult); | |||
} | |||
[Fact] | |||
public async Task GetOrder_ReturnsNotFound_WhenItemNotFound() | |||
{ | |||
// Arrange | |||
_queriesMock.Setup(queries => queries.GetOrder(1)) | |||
.Throws(new KeyNotFoundException()); | |||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||
// Act | |||
var notFoundResult = await controller.GetOrder(1); | |||
// Assert | |||
Assert.IsType<NotFoundResult>(notFoundResult); | |||
} | |||
[Fact] | |||
public async Task GetOrder_ReturnsOkObjecResult_WheItemFound() | |||
{ | |||
// Arrange | |||
_queriesMock.Setup(queries => queries.GetOrder(1)) | |||
.Returns(Task.FromResult(new object())); | |||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||
// Act | |||
var OkObjectResult = await controller.GetOrder(1); | |||
// Assert | |||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||
} | |||
[Fact] | |||
public async Task GetOrders_ReturnsOkObjectResult() | |||
{ | |||
// Arrange | |||
_queriesMock.Setup(queries => queries.GetOrders()) | |||
.Returns(Task.FromResult(new object())); | |||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||
// Act | |||
var OkObjectResult = await controller.GetOrders(); | |||
// Assert | |||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||
} | |||
[Fact] | |||
public async Task GetCardTypes() | |||
{ | |||
// Arrange | |||
_queriesMock.Setup(queries => queries.GetCardTypes()) | |||
.Returns(Task.FromResult(new object())); | |||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||
// Act | |||
var OkObjectResult = await controller.GetCardTypes(); | |||
// Assert | |||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||
} | |||
//Fakes | |||
private NewOrderRequest OrderFakeNotExpired() | |||
{ | |||
return new NewOrderRequest() | |||
{ | |||
CardTypeId = 1, | |||
CardExpiration = new DateTime(2020, 12, 12), | |||
Buyer = _userIdentity | |||
}; | |||
} | |||
private NewOrderRequest OrderFakeExpired() | |||
{ | |||
return new NewOrderRequest() | |||
{ | |||
CardTypeId = 1, | |||
CardExpiration = DateTime.Now.AddYears(-1) | |||
}; | |||
} | |||
} | |||
} |