Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding ability to place bid

  • Loading branch information...
commit fca29f32b2ef5205fa00dbcaff1652256278a273 1 parent cfd4033
@jchadwick jchadwick authored
View
0  ...ns/DataAnnotations/IsNotEmptyAttribute.cs → Core/DataAnnotations/IsNotEmptyAttribute.cs
File renamed without changes
View
0  ...nsions/DataAnnotations/UniqueAttribute.cs → Core/DataAnnotations/UniqueAttribute.cs
File renamed without changes
View
8 Core/Ebuy.Core.csproj
@@ -51,6 +51,8 @@
<Compile Include="DataAccess\DataContext.cs" />
<Compile Include="DataAccess\IRepository.cs" />
<Compile Include="DataAccess\Repository.cs" />
+ <Compile Include="DataAnnotations\IsNotEmptyAttribute.cs" />
+ <Compile Include="DataAnnotations\UniqueAttribute.cs" />
<Compile Include="Extensions\QueryableExtensions.cs" />
<Compile Include="Model\Auction.cs" />
<Compile Include="Model\Bid.cs" />
@@ -68,12 +70,6 @@
<Compile Include="Util\KeyGenerator.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\CustomExtensions\CustomExtensions.csproj">
- <Project>{6F8D99D7-A303-4BA7-9E29-7CCCD510FE78}</Project>
- <Name>CustomExtensions</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
<Compile Include="DataAccess\DataContext.Initializer.cs" />
<None Include="packages.config" />
</ItemGroup>
View
29 Core/Model/Auction.cs
@@ -35,6 +35,13 @@ public bool IsCompleted
public virtual User Owner { get; set; }
+ public virtual CurrencyCode CurrencyCode
+ {
+ get
+ {
+ return (StartingPrice != null) ? StartingPrice.Code : null;
+ }
+ }
public Auction()
{
@@ -44,18 +51,28 @@ public Auction()
}
- public void PostBid(User user, Currency bidAmount)
+ public Bid PostBid(User user, double bidAmount)
+ {
+ return PostBid(user, new Currency(CurrencyCode, bidAmount));
+ }
+
+ public Bid PostBid(User user, Currency bidAmount)
{
Contract.Requires(user != null);
- Contract.Requires(bidAmount != null);
- // TODO: Support multiple currencies
+ if (bidAmount.Code != CurrencyCode)
+ throw new InvalidBidException(bidAmount, WinningBid);
+
if (WinningBid != null && bidAmount.Value <= WinningBid.Amount.Value)
- throw new InvalidBidAmountException(bidAmount, WinningBid);
+ throw new InvalidBidException(bidAmount, WinningBid);
var bid = new Bid(user, this, bidAmount);
+
WinningBid = bid;
+
Bids.Add(bid);
+
+ return bid;
}
@@ -88,12 +105,12 @@ public class Metadata
}
}
- public class InvalidBidAmountException : Exception
+ public class InvalidBidException : Exception
{
public Currency BidAmount { get; set; }
public Bid WinningBid { get; set; }
- public InvalidBidAmountException(Currency bidAmount, Bid winningBid)
+ public InvalidBidException(Currency bidAmount, Bid winningBid = null)
{
BidAmount = bidAmount;
WinningBid = winningBid;
View
53 Core/Model/Currency.cs
@@ -7,6 +7,31 @@
namespace Ebuy
{
[ComplexType]
+ public class CurrencyCode
+ {
+ private readonly string _value;
+
+ public CurrencyCode(string value) : this()
+ {
+ _value = value;
+ }
+
+ private CurrencyCode()
+ {
+ }
+
+ public static implicit operator CurrencyCode(string code)
+ {
+ return new CurrencyCode(code);
+ }
+
+ public static implicit operator string(CurrencyCode code)
+ {
+ return code == null ? null : code._value;
+ }
+ }
+
+ [ComplexType]
public class Currency : IEquatable<Currency>
{
public static IDictionary<char, string> CurrencyCodesBySymbol = new Dictionary<char, string>() {
@@ -17,10 +42,10 @@ public class Currency : IEquatable<Currency>
};
public string Code { get; private set; }
- public decimal Value { get; private set; }
+ public double Value { get; private set; }
- public Currency(string code, decimal value)
+ public Currency(CurrencyCode code, double value)
{
Code = code;
Value = value;
@@ -32,7 +57,7 @@ public Currency(string currency)
Contract.Requires(currency.Length > 1);
Code = CurrencyCodesBySymbol[currency[0]];
- Value = decimal.Parse(currency.Substring(1));
+ Value = double.Parse(currency.Substring(1));
}
private Currency()
@@ -61,16 +86,26 @@ public override string ToString()
return string.Format("{0}{1}", symbol, Value);
}
- public static bool operator ==(Currency x, Currency y)
+ public static Currency operator +(Currency x, double amount)
+ {
+ Contract.Requires(x != null);
+ return new Currency(x.Code, x.Value + amount);
+ }
+
+ public static Currency operator -(Currency x, double amount)
+ {
+ Contract.Requires(x != null);
+ return new Currency(x.Code, x.Value - amount);
+ }
+
+ public static bool operator ==(Currency left, Currency right)
{
- if(x == null || y == null) return false;
- return x.Equals(y);
+ return Equals(left, right);
}
- public static bool operator !=(Currency x, Currency y)
+ public static bool operator !=(Currency left, Currency right)
{
- if (x == null || y == null) return true;
- return !x.Equals(y);
+ return !Equals(left, right);
}
public static implicit operator Currency(string currency)
View
11 CustomExtensions/CustomExtensions.csproj
@@ -77,8 +77,9 @@
<ItemGroup>
<Compile Include="Controllers\ControllerAction.cs" />
<Compile Include="Controllers\ControllerActions.cs" />
- <Compile Include="DataAnnotations\IsNotEmptyAttribute.cs" />
- <Compile Include="DataAnnotations\UniqueAttribute.cs" />
+ <Compile Include="Extensions\HttpContextExtensions.cs" />
+ <Compile Include="ModelBinding\DependencyResolverModelBinderProvider.cs" />
+ <Compile Include="ModelBinding\UserModelBinder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Routing\RouteAttribute.cs" />
<Compile Include="Routing\RouteGenerator.cs" />
@@ -86,6 +87,12 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Core\Ebuy.Core.csproj">
+ <Project>{EFD6F198-A4E8-419E-ABBC-8573B29ACC42}</Project>
+ <Name>Ebuy.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
View
19 CustomExtensions/Extensions/HttpContextExtensions.cs
@@ -0,0 +1,19 @@
+using System.Web;
+
+namespace Ebuy.Web.Extensions
+{
+ public static class HttpContextExtensions
+ {
+
+ public static User CurrentUser(this HttpContextBase context)
+ {
+ return context.Items["CurrentUser"] as User;
+ }
+
+ public static void CurrentUser(this HttpContextBase context, User user)
+ {
+ context.Items["CurrentUser"] = user;
+ }
+
+ }
+}
View
27 CustomExtensions/ModelBinding/DependencyResolverModelBinderProvider.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Diagnostics.Contracts;
+using System.Web.Mvc;
+
+namespace Ebuy.Web.ModelBinding
+{
+ public class DependencyResolverModelBinderProvider<TModelBinder> : IModelBinderProvider
+ where TModelBinder : IModelBinder
+ {
+ private readonly Func<Type, bool> _appliesToType;
+
+ public DependencyResolverModelBinderProvider(Func<Type, bool> appliesToType)
+ {
+ Contract.Requires(_appliesToType != null);
+
+ _appliesToType = appliesToType;
+ }
+
+ public IModelBinder GetBinder(Type modelType)
+ {
+ if (_appliesToType(modelType))
+ return DependencyResolver.Current.GetService<TModelBinder>();
+ else
+ return null;
+ }
+ }
+}
View
29 CustomExtensions/ModelBinding/UserModelBinder.cs
@@ -0,0 +1,29 @@
+using System.Web.Mvc;
+using Ebuy.DataAccess;
+using Ebuy.Web.Extensions;
+
+namespace Ebuy.Web.ModelBinding
+{
+ public class UserModelBinder : IModelBinder
+ {
+ private readonly IRepository _repository;
+
+ public UserModelBinder(IRepository repository)
+ {
+ _repository = repository;
+ }
+
+ public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
+ {
+ var context = controllerContext.HttpContext;
+ var identity = context.User.Identity;
+
+ var user = context.CurrentUser();
+
+ if (user == null && context.User.Identity.IsAuthenticated)
+ user = _repository.Single<User>(identity.Name);
+
+ return user;
+ }
+ }
+}
View
17 Website/App_Start/ModelBinding.cs
@@ -0,0 +1,17 @@
+using System.Web.Mvc;
+using Ebuy.Web.ModelBinding;
+using Ebuy.Website.App_Start;
+
+[assembly: WebActivator.PostApplicationStartMethod(typeof(ModelBinding), "Initialize")]
+
+namespace Ebuy.Website.App_Start
+{
+ public static class ModelBinding
+ {
+ public static void Initialize()
+ {
+ ModelBinderProviders.BinderProviders.Add(
+ new DependencyResolverModelBinderProvider<UserModelBinder>(type => typeof(User).IsAssignableFrom(type)));
+ }
+ }
+}
View
6 Website/Content/Site.css
@@ -638,3 +638,9 @@ ul#social li {
width: auto;
}
}
+
+
+.hint {
+ color: #D3D3D3;
+ font-size: 80%;
+}
View
18 Website/Controllers/AuctionsController.cs
@@ -39,9 +39,9 @@ public ActionResult Auction(string key)
[Route("auctions/{title}/{key}/bids")]
public ActionResult Bids(string key)
{
- var auction = _repository.Query<Auction>(x => x.Key == key);
+ var auction = _repository.Single<Auction>(key);
- if (auction == null || auction.Count() == 0)
+ if (auction == null)
return View("NotFound");
var bids = _repository.Query<Bid>(x => x.Auction.Key == key, "User", "Auction").ToArray();
@@ -60,5 +60,19 @@ public ActionResult Bids(string key)
return View("Bids", viewModel);
}
+ [Authorize]
+ [Route("auctions/{key}/bid")]
+ public ActionResult PlaceBid(string key, User user, double amount)
+ {
+ var auction = _repository.Single<Auction>(key);
+
+ if (auction == null)
+ return View("NotFound");
+
+ var bid = auction.PostBid(user, amount);
+ var viewModel = Mapper.DynamicMap<BidViewModel>(bid);
+
+ return View("SuccessfulBid", viewModel);
+ }
}
}
View
4 Website/Ebuy.Website.csproj
@@ -122,6 +122,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="App_Start\Areas.cs" />
+ <Compile Include="App_Start\ModelBinding.cs" />
<Compile Include="App_Start\Filters.cs" />
<Compile Include="App_Start\DataAccess.cs" />
<Compile Include="App_Start\NinjectMVC3.cs">
@@ -316,6 +317,9 @@
<ItemGroup>
<Content Include="Views\Auctions\Bids.cshtml" />
</ItemGroup>
+ <ItemGroup>
+ <Content Include="Views\Auctions\SuccessfulBid.cshtml" />
+ </ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
View
0  Website/Extensions/HtmlHelperExtensions.cs 100644 → 100755
File mode changed
View
0  Website/Extensions/UrlHelperExtensions.cs 100644 → 100755
File mode changed
View
16 Website/Models/AuctionViewModel.cs
@@ -104,5 +104,21 @@ public Currency WinningBidPrice
return null;
}
}
+
+ public Currency StartingPrice { get; set; }
+
+ public string CurrencyCode
+ {
+ get { return StartingPrice.Code; }
+ }
+
+ public Currency MinimumBid
+ {
+ get
+ {
+ var currentBidAmount = HasWinningBid ? WinningBid.Amount : StartingPrice;
+ return currentBidAmount + 0.01;
+ }
+ }
}
}
View
3  Website/Scripts/auction.js
@@ -0,0 +1,3 @@
+require(['jquery'], function() {
+
+});
View
5 Website/Views/Account/LogOn.cshtml
@@ -1,4 +1,4 @@
-@model Website.Models.LogOnModel
+@model LogOnModel
@{
ViewBag.Title = "Log On";
@@ -14,7 +14,8 @@
@Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
-@using (Html.BeginForm((string)ViewBag.FormAction, "Account")) {
+@using (Html.BeginForm((string)ViewBag.FormAction, "Account"))
+{
<fieldset>
<legend>Log On Form</legend>
<ol>
View
5 Website/Views/Account/Register.cshtml
@@ -1,4 +1,4 @@
-@model Website.Models.RegisterModel
+@model RegisterModel
@{
ViewBag.Title = "Register";
@@ -18,7 +18,8 @@
@Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.")
-@using (Html.BeginForm((string)ViewBag.FormAction, "Account")) {
+@using (Html.BeginForm((string)ViewBag.FormAction, "Account"))
+{
<fieldset>
<legend>Registration Form</legend>
<ol>
View
9 Website/Views/Auctions/Auction.cshtml
@@ -21,7 +21,14 @@
@Html.ActionLink("Bid History", "Bids", "Auctions", new { key = Model.Key }, null)
</p>
<p>
- <span><a href="StartNewAuction()">Bid Now</a></span>
+ @using (Html.BeginForm("PlaceBid", "Auctions", new { key = Model.Key }))
+ {
+ <label for="bid-amount">Amount: </label>
+ <input name="amount" type="text" value="@Model.MinimumBid.Value" required="true" autocomplete="false" autofocus="true" min="@Model.MinimumBid.Value" />
+ <span class="hint">Must be at least @Model.MinimumBid</span>
+
+ <input type="submit" value="Bid Now" />
+ }
</p>
</div>
View
11 Website/Views/Auctions/SuccessfulBid.cshtml
@@ -0,0 +1,11 @@
+@model BidViewModel
+
+@{
+ ViewBag.Title = "Bid Successful";
+}
+
+<h2>@ViewBag.Title</h2>
+
+<div>
+ <strong>Yay! You are the highest bidder at @Model.Amount!</strong>
+</div>
Please sign in to comment.
Something went wrong with that request. Please try again.