submit page, added categories, initial quotes/categories

This commit is contained in:
tmont 2011-02-12 23:53:43 +00:00
parent 4f98f46e1e
commit 215d3440b3
21 changed files with 876 additions and 78 deletions

View File

@ -1,30 +1,46 @@
using System;
using System.Collections.Generic;
using Iesi.Collections.Generic;
using JetBrains.Annotations;
using Portoa.Persistence;
namespace VideoGameQuotes.Api {
public class Game : Entity<Game, int> {
private readonly Iesi.Collections.Generic.ISet<System> systems = new HashedSet<System>();
private readonly Iesi.Collections.Generic.ISet<GamingSystem> systems = new HashedSet<GamingSystem>();
private readonly Iesi.Collections.Generic.ISet<Publisher> publishers = new HashedSet<Publisher>();
public Game() {
Created = DateTime.UtcNow;
}
public virtual string Website { get; set; }
public virtual User Creator { get; set; }
public virtual DateTime Created { get; set; }
public virtual IEnumerable<System> Systems { get { return systems; } }
public virtual IEnumerable<GamingSystem> Systems { get { return systems; } }
public virtual string Name { get; set; }
public virtual Publisher Publisher { get; set; }
public virtual IEnumerable<Publisher> Publishers { get { return publishers; } }
[CanBeNull]
public virtual byte[] Screenshot { get; set; }
public virtual Region Region { get; set; }
public virtual void AddSystem(System system) {
#region adding and removing stuff
public virtual Game AddSystem(GamingSystem system) {
systems.Add(system);
return this;
}
public virtual void RemoveSystem(System system) {
systems.Remove(system);
}
public virtual void ClearSystems() {
systems.Clear();
}
public virtual Game AddPublisher(Publisher publisher) {
publishers.Add(publisher);
return this;
}
public virtual void ClearPublishers() {
publishers.Clear();
}
#endregion
}
}

View File

@ -2,8 +2,8 @@
using Portoa.Persistence;
namespace VideoGameQuotes.Api {
public class System : Entity<System, int> {
public System() {
public class GamingSystem : Entity<GamingSystem, int> {
public GamingSystem() {
Created = DateTime.UtcNow;
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api">
<class name="Category" table="category">
<id column="category_id" name="Id" type="int">
<generator class="identity" />
</id>
<property name="Name" column="category_name" not-null="true" length="255"/>
<property name="Created" column="created" not-null="true" />
</class>
</hibernate-mapping>

View File

@ -1,23 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api">
<class name="Game" table="game">
<id column="game_id" name="Id" type="int">
<generator class="identity" />
</id>
<property name="Name" column="game_name" not-null="true" length="256"/>
<property name="Name" column="game_name" not-null="true" length="255"/>
<property name="Website" column="website" not-null="false" length="255"/>
<property name="Created" column="created" not-null="true" />
<property name="Screenshot" column="screenshot" not-null="false" length="10240" />
<property name="Region" column="game_region" not-null="true" />
<many-to-one name="Creator" column="creator" not-null="true" foreign-key="fk_game_user"/>
<many-to-one name="Publisher" column="publisher_id" not-null="false" foreign-key="fk_game_publisher" />
<set access="field" name="systems" table="game_system_map" cascade="save-update">
<key column="game_id" />
<many-to-many class="System" column="system_id" />
<many-to-many class="VideoGameQuotes.Api.GamingSystem" column="system_id" />
</set>
<set access="field" name="publishers" table="game_publisher_map" cascade="save-update">
<key column="game_id" />
<many-to-many class="VideoGameQuotes.Api.Publisher" column="publisher_id" />
</set>
</class>
</hibernate-mapping>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api">
<class name="System" table="system">
<class name="GamingSystem" table="system">
<id column="system_id" name="Id" type="int">
<generator class="identity" />
</id>
<property name="Name" column="system_name" not-null="true" length="256"/>
<property name="Name" column="system_name" not-null="true" length="255"/>
<property name="Abbreviation" column="system_abbreviation" not-null="false" length="12"/>
<property name="Created" column="created" not-null="true" />
<property name="ReleaseDate" column="release_date" not-null="false" />

View File

@ -13,14 +13,19 @@
<many-to-one name="Creator" column="creator" not-null="true" foreign-key="fk_quote_user"/>
<many-to-one name="Game" column="game_id" not-null="true" foreign-key="fk_quote_game" />
<set access="field" name="categories" table="quote_category_map" cascade="save-update">
<key column="quote_id" />
<many-to-many class="VideoGameQuotes.Api.Category" column="category_id" />
</set>
<set access="field" name="votes" table="vote" cascade="save-update">
<key column="quote_id" />
<one-to-many class="Vote" />
<one-to-many class="VideoGameQuotes.Api.Vote" />
</set>
<set access="field" name="flags" table="quote_flag" cascade="save-update">
<key column="quote_id" />
<one-to-many class="QuoteFlag" />
<one-to-many class="VideoGameQuotes.Api.QuoteFlag" />
</set>
</class>

View File

@ -1,4 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
using Portoa.Persistence;
namespace VideoGameQuotes.Api {
@ -7,6 +8,7 @@ namespace VideoGameQuotes.Api {
Created = DateTime.UtcNow;
}
[Required]
public virtual string Name { get; set; }
public virtual string Website { get; set; }
public virtual DateTime Created { get; set; }

View File

@ -8,6 +8,7 @@ namespace VideoGameQuotes.Api {
public class Quote : Entity<Quote, int> {
private readonly Iesi.Collections.Generic.ISet<Vote> votes = new HashedSet<Vote>();
private readonly Iesi.Collections.Generic.ISet<QuoteFlag> flags = new HashedSet<QuoteFlag>();
private readonly Iesi.Collections.Generic.ISet<Category> categories = new HashedSet<Category>();
public Quote() {
Created = DateTime.UtcNow;
@ -22,8 +23,29 @@ namespace VideoGameQuotes.Api {
public virtual IEnumerable<Vote> Votes { get { return votes; } }
public virtual IEnumerable<QuoteFlag> Flags { get { return flags; } }
public virtual IEnumerable<Category> Categories { get { return categories; } }
public virtual void VoteFor(User user, VoteDirection direction) {
#region adding and removing stuff
public virtual Quote AddCategory(Category category) {
categories.Add(category);
return this;
}
public virtual void ClearCategories() {
categories.Clear();
}
public virtual Quote AddFlag(QuoteFlag flag) {
flags.Add(flag);
return this;
}
public virtual void ClearFlags() {
flags.Clear();
}
#endregion
public virtual Quote VoteFor(User user, VoteDirection direction) {
var currentVote = votes.SingleOrDefault(vote => vote.Voter == user);
if (currentVote != null) {
if (currentVote.Direction == direction) {
@ -37,10 +59,47 @@ namespace VideoGameQuotes.Api {
} else {
votes.Add(new Vote { Direction = direction, Quote = this, Voter = user });
}
return this;
}
public virtual int UpVotes { get { return Votes.Count(vote => vote.Direction == VoteDirection.Up); } }
public virtual int DownVotes { get { return Votes.Count(vote => vote.Direction == VoteDirection.Down); } }
public virtual int NetVotes { get { return Votes.Sum(vote => (int)vote); } }
}
public static class QuoteExtensions {
public static string GetHumanReadableTimeSinceCreated(this Quote quote) {
var timespan = DateTime.UtcNow.Subtract(quote.Created);
if (timespan.TotalDays >= 365) {
var years = (int)Math.Round(timespan.TotalDays / 365);
return years == 1 ? "1 year ago" : years + " years ago";
}
if (timespan.TotalDays >= 50) {
var months = (int)Math.Round(timespan.TotalDays / 30);
return months == 1 ? "1 month ago" : months + " months ago";
}
if (timespan.TotalDays >= 10) {
var weeks = (int)Math.Round(timespan.TotalDays / 7);
return weeks == 1 ? "1 week ago" : weeks + " weeks ago";
}
if (timespan.TotalDays >= 1) {
return (int)timespan.TotalDays == 1 ? "1 day ago" : (int)timespan.TotalDays + " days ago";
}
if (timespan.TotalMinutes >= 90) {
return (int)timespan.TotalHours == 1 ? "1 hour ago" : (int)timespan.TotalHours + " hours ago";
}
if (timespan.TotalSeconds >= 90) {
return (int)timespan.TotalMinutes == 1 ? "1 minute ago" : (int)timespan.TotalMinutes + " minutes ago";
}
return (int)timespan.TotalSeconds == 1 ? "1 second ago" : (int)timespan.TotalSeconds + " seconds ago";
}
}
}

View File

@ -1,12 +1,18 @@
namespace VideoGameQuotes.Api {
using System;
namespace VideoGameQuotes.Api {
/// <summary>
/// The region for which a game is associated
/// </summary>
[Flags]
public enum Region {
Unknown = 0,
UnitedStates = 1,
NorthAmerica = 1,
Japan = 2,
Europe = 3,
Other = 4
Europe = 4,
PAL = 8,
Australia = 16,
All = NorthAmerica | Japan | Europe | PAL | Australia
}
}

View File

@ -56,6 +56,7 @@
<HintPath>..\..\Lib\Portoa.NHibernate.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@ -65,6 +66,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CannotVoteTwiceException.cs" />
<Compile Include="Category.cs" />
<Compile Include="Game.cs" />
<Compile Include="ICurrentUserProvider.cs" />
<Compile Include="Persistence\IUserRepository.cs" />
@ -75,7 +77,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="QuoteFlagType.cs" />
<Compile Include="Region.cs" />
<Compile Include="System.cs" />
<Compile Include="GamingSystem.cs" />
<Compile Include="User.cs" />
<Compile Include="UserGroup.cs" />
<Compile Include="Vote.cs" />
@ -84,7 +86,7 @@
<ItemGroup>
<EmbeddedResource Include="Mappings\User.hbm.xml" />
<EmbeddedResource Include="Mappings\Publisher.hbm.xml" />
<EmbeddedResource Include="Mappings\System.hbm.xml" />
<EmbeddedResource Include="Mappings\GamingSystem.hbm.xml" />
<EmbeddedResource Include="Mappings\Game.hbm.xml" />
<EmbeddedResource Include="Mappings\Quote.hbm.xml" />
</ItemGroup>
@ -94,6 +96,9 @@
<ItemGroup>
<EmbeddedResource Include="Mappings\QuoteFlag.hbm.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Mappings\Category.hbm.xml" />
</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 File

@ -0,0 +1,132 @@
using System;
using System.Linq;
using System.Web.Mvc;
using JetBrains.Annotations;
using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Security;
using VideoGameQuotes.Web.Services;
namespace VideoGameQuotes.Web.Controllers {
public class QuoteController : Controller {
private readonly IQuoteService quoteService;
private readonly ICurrentUserProvider currentUserProvider;
public QuoteController(IQuoteService quoteService, ICurrentUserProvider currentUserProvider) {
this.quoteService = quoteService;
this.currentUserProvider = currentUserProvider;
}
[IsValidUser]
public ActionResult Submit() {
var model = new QuoteSubmitModel();
ResetModel(model);
return View(model);
}
[HttpPost, IsValidUser]
public ActionResult Submit(QuoteSubmitModel model) {
if (!ModelState.IsValid) {
ResetModel(model);
return View(model);
}
try {
var quote = new Quote {
Creator = currentUserProvider.CurrentUser,
Game = GetGameFromModelData(model),
Text = model.QuoteText
};
if (quote.Game == null) {
ResetModel(model);
return View(model);
}
quote = quoteService.SaveQuote(quote);
return RedirectToAction("Quote", new { id = quote.Id });
} catch (Exception e) {
ModelState.AddModelError("save", e.Message);
ResetModel(model);
return View(model);
}
}
[CanBeNull]
private Game GetGameFromModelData(QuoteSubmitModel model) {
if (model.GameId > 0) {
try {
return quoteService.GetGame(model.GameId);
} catch {
throw new Exception("Unable to find game with ID " + model.GameId);
}
}
if (string.IsNullOrEmpty(model.GameName)) {
ModelState.AddModelError("GameName", "Game name must be non-empty");
return null;
}
//construct game from model data
var game = new Game {
Name = model.GameName,
Region = model.GameRegions.Aggregate(Region.Unknown, (current, next) => current | (Region)Enum.Parse(typeof(Region), next)),
Website = model.GameWebsite,
Creator = currentUserProvider.CurrentUser
};
//publishers
if ((model.PublisherIds != null && model.PublisherIds.Count > 0) || !string.IsNullOrEmpty(model.PublisherName)) {
//modifying publishers, so remove errthing
game.ClearPublishers();
if (model.PublisherIds != null && model.PublisherIds.Count > 0) {
foreach (var publisherId in model.PublisherIds) {
game.AddPublisher(quoteService.GetPublisher(publisherId));
}
}
if (!string.IsNullOrEmpty(model.PublisherName)) {
game.AddPublisher(new Publisher {
Name = model.PublisherName,
Website = model.PublisherWebsite
});
}
}
//systems
if ((model.SystemIds != null && model.SystemIds.Count > 0) || !string.IsNullOrEmpty(model.SystemName)) {
//modifying systems, so remove errthing
game.ClearSystems();
if (model.SystemIds != null && model.SystemIds.Count > 0) {
foreach (var systemId in model.SystemIds) {
game.AddSystem(quoteService.GetSystem(systemId));
}
}
if (!string.IsNullOrEmpty(model.SystemName)) {
game.AddSystem(new GamingSystem {
Name = model.SystemName,
Abbreviation = model.SystemAbbreviation,
ReleaseDate = model.SystemReleaseDate
});
}
}
return game;
}
private void ResetModel(QuoteSubmitModel model) {
model.AllGames = quoteService.GetAllGames().OrderBy(game => game.Name);
model.AllSystems = quoteService.GetAllSystems().OrderBy(system => system.ReleaseDate);
model.AllPublishers = quoteService.GetAllPublishers();
}
public ActionResult Quote(int id) {
return View(quoteService.GetQuote(id));
}
}
}

View File

@ -3,9 +3,12 @@ using System.Web.Routing;
using Microsoft.Practices.Unity;
using Portoa.Web;
using Portoa.Web.Unity;
using UnityGenerics;
using VideoGameQuotes.Api;
using VideoGameQuotes.Api.Persistence;
using VideoGameQuotes.Web.Controllers;
using VideoGameQuotes.Web.Security;
using VideoGameQuotes.Web.Services;
namespace VideoGameQuotes.Web {
public class MvcApplication : ApplicationBase {
@ -19,7 +22,9 @@ namespace VideoGameQuotes.Web {
Container
.AddNewExtension<LogAllMethodCalls>()
.RegisterType<ICurrentUserProvider, SessionBasedUserProvider>()
.RegisterType<IsValidUserAttribute>(new InjectionProperty<IsValidUserAttribute>(attr => attr.UserProvider))
.RegisterType<IUserService, UserService>()
.RegisterType<IQuoteService, QuoteService>()
.RegisterType<IUserRepository, UserRepository>();
}
@ -29,6 +34,8 @@ namespace VideoGameQuotes.Web {
routes.MapRoute("about", "about", new { controller = "Home", action = "About" });
routes.MapRoute("contact", "contact", new { controller = "Home", action = "Contact" });
routes.MapRoute("submit", "submit", new { controller = "Quote", action = "Submit" });
routes.MapRoute("individual-quote", "q/{id}/{*text}", new { controller = "Quote", action = "Quote" }, new { id = @"\d+" });
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Portoa.Web.Util;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Models {
public class QuoteSubmitModel {
[Required, DisplayName("Quote")]
public string QuoteText { get; set; }
public int GameId { get; set; }
//if a new game is created
[DisplayName("Name")]
public string GameName { get; set; }
[DisplayName("Website")]
public string GameWebsite { get; set; }
[DisplayName("Region")]
public IList<string> GameRegions { get; set; }
[DisplayName("Publishers")]
public IList<int> PublisherIds { get; set; }
[DisplayName("Systems")]
public IList<int> SystemIds { get; set; }
//if a new publisher is created
[DisplayName("Name")]
public string PublisherName { get; set; }
[DisplayName("Website")]
public string PublisherWebsite { get; set; }
//if a new system is created
[DisplayName("Name")]
public string SystemName { get; set; }
[DisplayName("Abbreviation")]
public string SystemAbbreviation { get; set; }
[DisplayName("Release Date")]
public DateTime SystemReleaseDate { get; set; }
public IEnumerable<Game> AllGames { get; set; }
public IEnumerable<GamingSystem> AllSystems { get; set; }
public IEnumerable<Publisher> AllPublishers { get; set; }
public IEnumerable<SelectListItem> GetGameList() {
return new[] { new SelectListItem { Value = "0", Text = "--none--" } }
.Concat(AllGames.Select(game => new SelectListItem { Value = game.Id.ToString(), Text = game.Name }));
}
private static string MakeTable<T>(int cellsPerRow, IEnumerable<T> items, Func<T, string> cellDataCallback) {
var table = new TagBuilder("table");
var count = 0;
var row = new TagBuilder("tr");
var cell = new TagBuilder("td");
foreach (var item in items) {
if (count % cellsPerRow == 0) {
if (count > 0) {
table.InnerHtml += row.ToString(TagRenderMode.Normal);
}
row.InnerHtml = string.Empty;
}
cell.InnerHtml = cellDataCallback(item);
row.InnerHtml += cell.ToString(TagRenderMode.Normal);
count++;
}
if (count > 0) {
//last row
table.InnerHtml += row.ToString(TagRenderMode.Normal);
}
return table.ToString(TagRenderMode.Normal);
}
public string MakePublisherTable(HtmlHelper<QuoteSubmitModel> html, int cellsPerRow = 4) {
return MakeTable(cellsPerRow, AllPublishers, publisher => {
var id = "publisher_" + publisher.Id;
return html.CheckBox("PublisherIds", new { id }) + html.Label(publisher.Name, id);
});
}
public string MakeSystemTable(HtmlHelper<QuoteSubmitModel> html, int cellsPerRow = 8) {
return MakeTable(cellsPerRow, AllSystems, system => {
var id = "system_" + system.Id;
return html.CheckBox("SystemIds", new { id }) + html.Label(system.Abbreviation, id, new { title = system.Name });
});
}
}
}

View File

@ -0,0 +1,31 @@
using System.Net;
using System.Web.Mvc;
using Portoa.Web;
using Portoa.Web.ErrorHandling;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Security {
[NeedsBuildUp]
public class IsValidUserAttribute : ActionFilterAttribute {
public IsValidUserAttribute() {
Group = UserGroup.User;
}
public ICurrentUserProvider UserProvider { get; set; }
public UserGroup Group { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var allowedToExecuteAction = UserProvider != null
&& UserProvider.CurrentUser != null
&& UserProvider.CurrentUser.Group >= Group;
if (!allowedToExecuteAction) {
filterContext.Result = new ErrorViewResult {
Message = "You are not a verified user (are you hiding your IP address?)",
StatusCode = HttpStatusCode.Forbidden,
ViewName = "Forbidden"
};
}
}
}
}

View File

@ -0,0 +1,75 @@
using System.Collections.Generic;
using Portoa.Persistence;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Services {
public interface IQuoteService {
Game GetGame(int id);
IEnumerable<Game> GetAllGames();
IEnumerable<GamingSystem> GetAllSystems();
IEnumerable<Publisher> GetAllPublishers();
Quote SaveQuote(Quote quote);
Quote GetQuote(int id);
Publisher GetPublisher(int id);
GamingSystem GetSystem(int systemId);
}
public class QuoteService : IQuoteService {
private readonly IRepository<Quote> quoteRepository;
private readonly IRepository<Game> gameRepository;
private readonly IRepository<GamingSystem> systemRepository;
private readonly IRepository<Publisher> publisherRepository;
public QuoteService(
IRepository<Quote> quoteRepository,
IRepository<Game> gameRepository,
IRepository<GamingSystem> systemRepository,
IRepository<Publisher> publisherRepository
) {
this.quoteRepository = quoteRepository;
this.gameRepository = gameRepository;
this.systemRepository = systemRepository;
this.publisherRepository = publisherRepository;
}
[UnitOfWork]
public Game GetGame(int id) {
return gameRepository.FindById(id);
}
[UnitOfWork]
public IEnumerable<Game> GetAllGames() {
return gameRepository.Records;
}
[UnitOfWork]
public IEnumerable<Api.GamingSystem> GetAllSystems() {
return systemRepository.Records;
}
[UnitOfWork]
public IEnumerable<Publisher> GetAllPublishers() {
return publisherRepository.Records;
}
[UnitOfWork]
public Quote SaveQuote(Quote quote) {
return quoteRepository.Save(quote);
}
[UnitOfWork]
public Quote GetQuote(int id) {
return quoteRepository.FindById(id);
}
[UnitOfWork]
public Publisher GetPublisher(int id) {
return publisherRepository.FindById(id);
}
[UnitOfWork]
public GamingSystem GetSystem(int systemId) {
return systemRepository.FindById(systemId);
}
}
}

View File

@ -79,14 +79,21 @@
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="UnityGenerics">
<HintPath>..\..\Lib\UnityGenerics.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Security\IsValidUserAttribute.cs" />
<Compile Include="Controllers\QuoteController.cs" />
<Compile Include="Services\QuoteService.cs" />
<Compile Include="Default.aspx.cs">
<DependentUpon>Default.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Models\ContactModel.cs" />
<Compile Include="Models\QuoteSubmitModel.cs" />
<Compile Include="Security\SessionBasedUserProvider.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
@ -106,6 +113,8 @@
<Content Include="Views\Home\About.aspx" />
<Content Include="Views\Home\Contact.aspx" />
<Content Include="Views\Home\ContactSuccess.aspx" />
<Content Include="Views\Quote\Quote.aspx" />
<Content Include="Views\Quote\Submit.aspx" />
<Content Include="Views\Shared\ExceptionView.ascx" />
<Content Include="Views\Shared\Forbidden.aspx" />
<Content Include="Views\Shared\NotFound.aspx" />

View File

@ -0,0 +1,24 @@
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Api.Quote>" MasterPageFile="~/Views/Shared/Site.Master" %>
<%@ Import Namespace="VideoGameQuotes.Api" %>
<asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent"><%: Model.Game.Name %></asp:Content>
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<div class="quote">
<span class="vote-for" title="I like this quote"><a href="#" id="vote-for">&uarr;</a></span>
<span class="vote-against" title="I dislike this quote"><a href="#" id="vote-against">&darr;</a></span>
<span class="quote-report-link" title="report this quote as inaccurate, fake, spam, duplicate, etc."><a href="#" id="quote-report-link">report</a></span>
<p class="quote-text">
<%: Model.Text %>
</p>
</div>
<div class="quote-details">
<dl>
<dt>Game</dt>
<dd><%= Html.ActionLink(Model.Game.Name, "Index", "Quote", new { game = Model.Game.Id }, null) %></dd>
<dt>Added</dt>
<dd><%: Model.GetHumanReadableTimeSinceCreated() %></dd>
</dl>
</div>
</asp:Content>
<asp:Content runat="server" ID="DeferrableScripts" ContentPlaceHolderID="DeferrableScripts"></asp:Content>

View File

@ -0,0 +1,155 @@
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.QuoteSubmitModel>" MasterPageFile="~/Views/Shared/Site.Master" %>
<%@ Import Namespace="Portoa.Web.Util" %>
<asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Submit New Quote</asp:Content>
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<h2>Submit New Quote</h2>
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
<p>
<span id="game-select">
<%= Html.Label("Game", "GameId") %>
<br />
<%= Html.DropDownListFor(model => model.GameId, Model.GetGameList()) %>
</span>
<a href="#" id="create-game-link">Create new game</a>
</p>
<div id="create-game-form">
<fieldset>
<legend>Create new game</legend>
<p>
<%= Html.LabelFor(model => model.GameName) %>
<br />
<%= Html.TextBoxFor(model => model.GameName) %>
</p>
<p>
<%= Html.LabelFor(model => model.GameWebsite) %> <small>(link to Wikipedia page or something)</small>
<br />
<%= Html.TextBoxFor(model => model.GameWebsite) %>
</p>
<p>
<span id="system-select">
<%= Html.LabelFor(model => model.SystemIds) %>
<br />
<%= Model.MakeSystemTable(Html) %>
</span>
<a href="#" id="create-system-link">Create new system</a>
</p>
<div id="create-system-form">
<fieldset>
<legend>Create new system</legend>
<p>
<%= Html.LabelFor(model => model.SystemName) %>
<br />
<%= Html.TextBoxFor(model => model.SystemName) %>
</p>
<p>
<%= Html.LabelFor(model => model.SystemAbbreviation) %>
<br />
<%= Html.TextBoxFor(model => model.SystemAbbreviation) %>
</p>
<p>
<%= Html.LabelFor(model => model.SystemReleaseDate) %>
<br />
<%= Html.TextBox("SystemReleaseDate", DateTime.UtcNow.ToString("yyyy-MM-dd")) %>
</p>
</fieldset>
</div>
<p>
<span id="publisher-select">
<%= Html.LabelFor(model => model.PublisherIds) %>
<br />
<%= Model.MakePublisherTable(Html) %>
</span>
<a href="#" id="create-publisher-link">Create new publisher</a>
</p>
<div id="create-publisher-form">
<fieldset>
<legend>Create new publisher</legend>
<p>
<%= Html.LabelFor(model => model.PublisherName) %>
<br />
<%= Html.TextBoxFor(model => model.PublisherName) %>
</p>
<p>
<%= Html.LabelFor(model => model.PublisherWebsite) %>
<br />
<%= Html.TextBoxFor(model => model.PublisherWebsite) %>
</p>
</fieldset>
</div>
</fieldset>
</div>
<p>
<%= Html.LabelFor(model => model.QuoteText) %>
<br />
<%= Html.TextAreaFor(model => model.QuoteText) %>
</p>
<%= Html.Submit("Submit") %>
<% } %>
</asp:Content>
<asp:Content runat="server" ID="DeferrableScripts" ContentPlaceHolderID="DeferrableScripts">
<script type="text/javascript">//<![CDATA[
$(document).ready(function() {
$("#create-game-link").click(function() {
//show the create game form
var $form = $("#create-game-form");
if ($form.is(":visible")) {
$("#create-game-link").text("Create new game");
} else {
$("#create-game-link").text("Use existing game");
$("#GameId").val("0");
}
$form.toggle();
$("#game-select").toggle();
return false;
});
$("#create-system-link").click(function() {
//show the create game form
var $form = $("#create-system-form");
if ($form.is(":visible")) {
$("#create-system-link").text("Create new system");
} else {
$("#create-system-link").text("Use existing system");
}
$form.toggle();
$("#system-select").toggle();
return false;
});
$("#create-publisher-link").click(function() {
//show the create game form
var $form = $("#create-publisher-form");
if ($form.is(":visible")) {
$("#create-publisher-link").text("Create new publisher");
} else {
$("#create-publisher-link").text("Use existing publisher");
}
$form.toggle();
$("#publisher-select").toggle();
return false;
});
});
//]]></script>
</asp:Content>

View File

@ -27,6 +27,15 @@ p {
padding: 2px;
line-height: 1.2em;
}
fieldset {
border: 1px solid #999999;
padding: 5px;
}
legend {
font-weight: bold;
margin-left: 20px;
padding: 5px;
}
.inset {
margin-left: 20px;
@ -123,6 +132,10 @@ p {
border-bottom: 2px solid #000000;
}
#create-game-form, #create-system-form {
display: none;
}
#footer {
text-align: center;
font-size: 75%;

View File

@ -1,4 +1,5 @@
using System;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
@ -37,29 +38,40 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
tx.Commit();
}
var nes = new System { Abbreviation = "NES", Name = "Nintendo Entertainment System", ReleaseDate = new DateTime(1985, 10, 18) };
var snes = new System { Abbreviation = "SNES", Name = "Super Nintendo Entertainment System", ReleaseDate = new DateTime(1991, 8, 23) };
var genny = new System { Abbreviation = "Genesis", Name = "Sega Genesis", ReleaseDate = new DateTime(1989, 10, 14) };
var ps = new System { Abbreviation = "PS", Name = "PlayStation", ReleaseDate = new DateTime(1995, 9, 9) };
var ps2 = new System { Abbreviation = "PS2", Name = "PlayStation 2", ReleaseDate = new DateTime(2000, 3, 4) };
var xbox = new System { Abbreviation = "Xbox", Name = "Xbox", ReleaseDate = new DateTime(2002, 2, 22) };
var n64 = new System { Abbreviation = "N64", Name = "Nintendo 64", ReleaseDate = new DateTime(1996, 9, 29) };
var gcn = new System { Abbreviation = "GCN", Name = "Nintendo GameCube", ReleaseDate = new DateTime(2001, 11, 18) };
var dc = new System { Abbreviation = "DC", Name = "Dreamcast", ReleaseDate = new DateTime(1999, 9, 9) };
var wii = new System { Abbreviation = "Wii", Name = "Wii", ReleaseDate = new DateTime(2006, 11, 19) };
var xbox360 = new System { Abbreviation = "360", Name = "Xbox 360", ReleaseDate = new DateTime(2005, 11, 16) };
var ps3 = new System { Abbreviation = "PS3", Name = "PlayStation 3", ReleaseDate = new DateTime(2006, 11, 17) };
var pc = new System { Abbreviation = "PC", Name = "Personal Computer", ReleaseDate = new DateTime(1980, 1, 1) };
CreateInitialData(session, admin);
}
var gb = new System { Abbreviation = "GB", Name = "Game Boy", ReleaseDate = new DateTime(1989, 7, 31) };
var gbc = new System { Abbreviation = "GBC", Name = "Game Boy Color", ReleaseDate = new DateTime(1998, 11, 18) };
var gba = new System { Abbreviation = "GBA", Name = "Game Boy Advance", ReleaseDate = new DateTime(2001, 6, 11) };
var nds = new System { Abbreviation = "NES", Name = "Nintendo Entertainment System", ReleaseDate = new DateTime(1985, 10, 18) };
var psp = new System { Abbreviation = "PSP", Name = "PlayStation Portable", ReleaseDate = new DateTime(2005, 3, 24) };
private static void CreateInitialData(ISession session, User creator) {
#region systems
var fds = new GamingSystem { Abbreviation = "FDS", Name = "Family Computer Disk System", ReleaseDate = new DateTime(1986, 2, 21) };
var nes = new GamingSystem { Abbreviation = "NES", Name = "Nintendo Entertainment System", ReleaseDate = new DateTime(1985, 10, 18) };
var snes = new GamingSystem { Abbreviation = "SNES", Name = "Super Nintendo Entertainment System", ReleaseDate = new DateTime(1991, 8, 23) };
var genny = new GamingSystem { Abbreviation = "Genesis", Name = "Sega Genesis", ReleaseDate = new DateTime(1989, 10, 14) };
var ps = new GamingSystem { Abbreviation = "PS", Name = "PlayStation", ReleaseDate = new DateTime(1995, 9, 9) };
var ps2 = new GamingSystem { Abbreviation = "PS2", Name = "PlayStation 2", ReleaseDate = new DateTime(2000, 3, 4) };
var xbox = new GamingSystem { Abbreviation = "Xbox", Name = "Xbox", ReleaseDate = new DateTime(2002, 2, 22) };
var n64 = new GamingSystem { Abbreviation = "N64", Name = "Nintendo 64", ReleaseDate = new DateTime(1996, 9, 29) };
var gcn = new GamingSystem { Abbreviation = "GCN", Name = "Nintendo GameCube", ReleaseDate = new DateTime(2001, 11, 18) };
var dc = new GamingSystem { Abbreviation = "DC", Name = "Dreamcast", ReleaseDate = new DateTime(1999, 9, 9) };
var wii = new GamingSystem { Abbreviation = "Wii", Name = "Wii", ReleaseDate = new DateTime(2006, 11, 19) };
var xbox360 = new GamingSystem { Abbreviation = "360", Name = "Xbox 360", ReleaseDate = new DateTime(2005, 11, 16) };
var ps3 = new GamingSystem { Abbreviation = "PS3", Name = "PlayStation 3", ReleaseDate = new DateTime(2006, 11, 17) };
var tgfx = new GamingSystem { Abbreviation = "TGfx", Name = "TurboGrafx-16 Entertainment SuperSystem", ReleaseDate = new DateTime(1989, 10, 29) };
var pc = new GamingSystem { Abbreviation = "PC", Name = "Personal Computer", ReleaseDate = new DateTime(1980, 1, 1) };
var gb = new GamingSystem { Abbreviation = "GB", Name = "Game Boy", ReleaseDate = new DateTime(1989, 7, 31) };
var gbc = new GamingSystem { Abbreviation = "GBC", Name = "Game Boy Color", ReleaseDate = new DateTime(1998, 11, 18) };
var gba = new GamingSystem { Abbreviation = "GBA", Name = "Game Boy Advance", ReleaseDate = new DateTime(2001, 6, 11) };
var nds = new GamingSystem { Abbreviation = "NDS", Name = "Nintendo DS", ReleaseDate = new DateTime(2004, 11, 21) };
var psp = new GamingSystem { Abbreviation = "PSP", Name = "PlayStation Portable", ReleaseDate = new DateTime(2005, 3, 24) };
var arcade = new GamingSystem { Abbreviation = "Arcade", Name = "Arcade", ReleaseDate = new DateTime(1966, 1, 1) };
using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<System>(session);
var repo = new NHibernateRepository<GamingSystem>(session);
repo.Save(nes);
repo.Save(fds);
repo.Save(snes);
repo.Save(genny);
repo.Save(ps);
@ -77,9 +89,89 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
repo.Save(gba);
repo.Save(nds);
repo.Save(psp);
repo.Save(arcade);
repo.Save(tgfx);
tx.Commit();
}
}
#endregion
#region publishers
var nintendo = new Publisher { Name = "Nintendo", Website = "http://www.nintendo.com/" };
var snk = new Publisher { Name = "SNK", Website = "http://www.snkplaymoreusa.com/" };
var sega = new Publisher { Name = "Sega", Website = "http://www.sega.com/" };
var taito = new Publisher { Name = "Taito", Website = "http://www.taito.com/" };
var kaga = new Publisher { Name = "Kaga Create", Website = "http://www.kaga-create.co.jp/" };
using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Publisher>(session);
repo.Save(nintendo);
repo.Save(snk);
repo.Save(sega);
repo.Save(taito);
repo.Save(kaga);
tx.Commit();
}
#endregion
#region categories
var engrish = new Category { Name = "Engrish" };
var danger = new Category { Name = "Danger" };
using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Category>(session);
repo.Save(engrish);
repo.Save(danger);
tx.Commit();
}
#endregion
#region games
var loz = new Game { Creator = creator, Name = "The Legend of Zelda", Website = "http://www.zelda.com/", Region = Region.NorthAmerica | Region.Japan | Region.PAL }
.AddSystem(nes)
.AddSystem(gba)
.AddSystem(gcn)
.AddSystem(fds)
.AddPublisher(nintendo);
var crystalis = new Game { Creator = creator, Name = "Crystalis", Website = "http://en.wikipedia.org/wiki/Crystalis", Region = Region.Japan | Region.NorthAmerica }
.AddSystem(nes)
.AddSystem(gbc)
.AddPublisher(snk)
.AddPublisher(nintendo);
var zeroWing = new Game { Creator = creator, Name = "Zero Wing", Website = "http://en.wikipedia.org/wiki/Zero_Wing", Region = Region.Japan | Region.Europe }
.AddSystem(genny)
.AddSystem(arcade)
.AddSystem(tgfx)
.AddPublisher(taito)
.AddPublisher(kaga)
.AddPublisher(sega);
using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Game>(session);
repo.Save(loz);
repo.Save(crystalis);
repo.Save(zeroWing);
tx.Commit();
}
#endregion
#region quotes
var allYourBase = new Quote { Creator = creator, Game = zeroWing, Text = "All your base are belong to us" }
.AddCategory(engrish)
.VoteFor(creator, VoteDirection.Up);
var dangerousToGoAlone = new Quote { Creator = creator, Game = loz, Text = "It is dangerous to go alone." }
.AddCategory(danger)
.VoteFor(creator, VoteDirection.Up);
using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<Quote>(session);
repo.Save(allYourBase);
repo.Save(dangerousToGoAlone);
tx.Commit();
}
#endregion
}
}
}

View File

@ -12,11 +12,7 @@ alter table game drop foreign key fk_game_user
;
alter table game drop foreign key fk_game_publisher
;
alter table game_system_map drop foreign key FK5B40970FD86811D9
alter table game_system_map drop foreign key FK5B40970FE5573E38
;
@ -24,6 +20,14 @@ alter table game_system_map drop foreign key FK5B40970FD968AB11
;
alter table game_publisher_map drop foreign key FKC48C1B2A6659BAD
;
alter table game_publisher_map drop foreign key FKC48C1B2D968AB11
;
alter table quote_flag drop foreign key fk_flag_user
;
@ -39,15 +43,23 @@ alter table game_quote drop foreign key fk_quote_user
alter table game_quote drop foreign key fk_quote_game
;
alter table quote_category_map drop foreign key FK5892F84657AD8111
;
alter table quote_category_map drop foreign key FK5892F846C2AA09DD
;
drop table if exists vote;
drop table if exists game;
drop table if exists game_system_map;
drop table if exists publisher;
drop table if exists game_publisher_map;
drop table if exists system;
drop table if exists publisher;
drop table if exists vgquote_user;
@ -55,6 +67,12 @@ alter table game_quote drop foreign key fk_quote_game
drop table if exists game_quote;
drop table if exists quote_category_map;
drop table if exists system;
drop table if exists category;
create table vote (
vote_id INTEGER NOT NULL AUTO_INCREMENT,
created DATETIME not null,
@ -66,12 +84,12 @@ alter table game_quote drop foreign key fk_quote_game
create table game (
game_id INTEGER NOT NULL AUTO_INCREMENT,
game_name TEXT not null,
game_name VARCHAR(255) not null,
website VARCHAR(255),
created DATETIME not null,
screenshot BLOB,
game_region INTEGER not null,
creator INTEGER not null,
publisher_id INTEGER,
primary key (game_id)
);
@ -81,6 +99,12 @@ alter table game_quote drop foreign key fk_quote_game
primary key (game_id, system_id)
);
create table game_publisher_map (
game_id INTEGER not null,
publisher_id INTEGER not null,
primary key (game_id, publisher_id)
);
create table publisher (
publisher_id INTEGER NOT NULL AUTO_INCREMENT,
publisher_name TEXT not null,
@ -89,18 +113,10 @@ alter table game_quote drop foreign key fk_quote_game
primary key (publisher_id)
);
create table system (
system_id INTEGER NOT NULL AUTO_INCREMENT,
system_name TEXT not null,
system_abbreviation VARCHAR(12),
created DATETIME not null,
release_date DATETIME,
primary key (system_id)
);
create table vgquote_user (
user_id INTEGER NOT NULL AUTO_INCREMENT,
username VARCHAR(50) not null unique,
username VARCHAR(50),
ip_address VARCHAR(40),
created DATETIME not null,
user_group INTEGER not null,
user_password VARCHAR(100),
@ -128,6 +144,28 @@ alter table game_quote drop foreign key fk_quote_game
primary key (quote_id)
);
create table quote_category_map (
quote_id INTEGER not null,
category_id INTEGER not null,
primary key (quote_id, category_id)
);
create table system (
system_id INTEGER NOT NULL AUTO_INCREMENT,
system_name VARCHAR(255) not null,
system_abbreviation VARCHAR(12),
created DATETIME not null,
release_date DATETIME,
primary key (system_id)
);
create table category (
category_id INTEGER NOT NULL AUTO_INCREMENT,
category_name VARCHAR(255) not null,
created DATETIME not null,
primary key (category_id)
);
alter table vote
add index (voter_id),
add constraint fk_vote_user
@ -146,15 +184,9 @@ alter table game_quote drop foreign key fk_quote_game
foreign key (creator)
references vgquote_user (user_id);
alter table game
add index (publisher_id),
add constraint fk_game_publisher
foreign key (publisher_id)
references publisher (publisher_id);
alter table game_system_map
add index (system_id),
add constraint FK5B40970FD86811D9
add constraint FK5B40970FE5573E38
foreign key (system_id)
references system (system_id);
@ -164,6 +196,18 @@ alter table game_quote drop foreign key fk_quote_game
foreign key (game_id)
references game (game_id);
alter table game_publisher_map
add index (publisher_id),
add constraint FKC48C1B2A6659BAD
foreign key (publisher_id)
references publisher (publisher_id);
alter table game_publisher_map
add index (game_id),
add constraint FKC48C1B2D968AB11
foreign key (game_id)
references game (game_id);
alter table quote_flag
add index (user_id),
add constraint fk_flag_user
@ -187,3 +231,15 @@ alter table game_quote drop foreign key fk_quote_game
add constraint fk_quote_game
foreign key (game_id)
references game (game_id);
alter table quote_category_map
add index (category_id),
add constraint FK5892F84657AD8111
foreign key (category_id)
references category (category_id);
alter table quote_category_map
add index (quote_id),
add constraint FK5892F846C2AA09DD
foreign key (quote_id)
references game_quote (quote_id);