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;
using System.Collections.Generic; using System.Collections.Generic;
using Iesi.Collections.Generic; using Iesi.Collections.Generic;
using JetBrains.Annotations;
using Portoa.Persistence; using Portoa.Persistence;
namespace VideoGameQuotes.Api { namespace VideoGameQuotes.Api {
public class Game : Entity<Game, int> { 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() { public Game() {
Created = DateTime.UtcNow; Created = DateTime.UtcNow;
} }
public virtual string Website { get; set; }
public virtual User Creator { get; set; } public virtual User Creator { get; set; }
public virtual DateTime Created { 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 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 byte[] Screenshot { get; set; }
public virtual Region Region { 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); systems.Add(system);
return this;
} }
public virtual void RemoveSystem(System system) { public virtual void ClearSystems() {
systems.Remove(system); 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; using Portoa.Persistence;
namespace VideoGameQuotes.Api { namespace VideoGameQuotes.Api {
public class System : Entity<System, int> { public class GamingSystem : Entity<GamingSystem, int> {
public System() { public GamingSystem() {
Created = DateTime.UtcNow; 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"?> <?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api"> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api">
<class name="Game" table="game"> <class name="Game" table="game">
<id column="game_id" name="Id" type="int"> <id column="game_id" name="Id" type="int">
<generator class="identity" /> <generator class="identity" />
</id> </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="Created" column="created" not-null="true" />
<property name="Screenshot" column="screenshot" not-null="false" length="10240" /> <property name="Screenshot" column="screenshot" not-null="false" length="10240" />
<property name="Region" column="game_region" not-null="true" /> <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="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"> <set access="field" name="systems" table="game_system_map" cascade="save-update">
<key column="game_id" /> <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> </set>
</class> </class>
</hibernate-mapping> </hibernate-mapping>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VideoGameQuotes.Api" namespace="VideoGameQuotes.Api"> <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"> <id column="system_id" name="Id" type="int">
<generator class="identity" /> <generator class="identity" />
</id> </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="Abbreviation" column="system_abbreviation" not-null="false" length="12"/>
<property name="Created" column="created" not-null="true" /> <property name="Created" column="created" not-null="true" />
<property name="ReleaseDate" column="release_date" not-null="false" /> <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="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" /> <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"> <set access="field" name="votes" table="vote" cascade="save-update">
<key column="quote_id" /> <key column="quote_id" />
<one-to-many class="Vote" /> <one-to-many class="VideoGameQuotes.Api.Vote" />
</set> </set>
<set access="field" name="flags" table="quote_flag" cascade="save-update"> <set access="field" name="flags" table="quote_flag" cascade="save-update">
<key column="quote_id" /> <key column="quote_id" />
<one-to-many class="QuoteFlag" /> <one-to-many class="VideoGameQuotes.Api.QuoteFlag" />
</set> </set>
</class> </class>

View File

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

View File

@ -8,6 +8,7 @@ namespace VideoGameQuotes.Api {
public class Quote : Entity<Quote, int> { public class Quote : Entity<Quote, int> {
private readonly Iesi.Collections.Generic.ISet<Vote> votes = new HashedSet<Vote>(); 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<QuoteFlag> flags = new HashedSet<QuoteFlag>();
private readonly Iesi.Collections.Generic.ISet<Category> categories = new HashedSet<Category>();
public Quote() { public Quote() {
Created = DateTime.UtcNow; Created = DateTime.UtcNow;
@ -22,8 +23,29 @@ namespace VideoGameQuotes.Api {
public virtual IEnumerable<Vote> Votes { get { return votes; } } public virtual IEnumerable<Vote> Votes { get { return votes; } }
public virtual IEnumerable<QuoteFlag> Flags { get { return flags; } } 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); var currentVote = votes.SingleOrDefault(vote => vote.Voter == user);
if (currentVote != null) { if (currentVote != null) {
if (currentVote.Direction == direction) { if (currentVote.Direction == direction) {
@ -37,10 +59,47 @@ namespace VideoGameQuotes.Api {
} else { } else {
votes.Add(new Vote { Direction = direction, Quote = this, Voter = user }); 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 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 DownVotes { get { return Votes.Count(vote => vote.Direction == VoteDirection.Down); } }
public virtual int NetVotes { get { return Votes.Sum(vote => (int)vote); } } 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> /// <summary>
/// The region for which a game is associated /// The region for which a game is associated
/// </summary> /// </summary>
[Flags]
public enum Region { public enum Region {
Unknown = 0, Unknown = 0,
UnitedStates = 1, NorthAmerica = 1,
Japan = 2, Japan = 2,
Europe = 3, Europe = 4,
Other = 4 PAL = 8,
Australia = 16,
All = NorthAmerica | Japan | Europe | PAL | Australia
} }
} }

View File

@ -56,6 +56,7 @@
<HintPath>..\..\Lib\Portoa.NHibernate.dll</HintPath> <HintPath>..\..\Lib\Portoa.NHibernate.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
@ -65,6 +66,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CannotVoteTwiceException.cs" /> <Compile Include="CannotVoteTwiceException.cs" />
<Compile Include="Category.cs" />
<Compile Include="Game.cs" /> <Compile Include="Game.cs" />
<Compile Include="ICurrentUserProvider.cs" /> <Compile Include="ICurrentUserProvider.cs" />
<Compile Include="Persistence\IUserRepository.cs" /> <Compile Include="Persistence\IUserRepository.cs" />
@ -75,7 +77,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="QuoteFlagType.cs" /> <Compile Include="QuoteFlagType.cs" />
<Compile Include="Region.cs" /> <Compile Include="Region.cs" />
<Compile Include="System.cs" /> <Compile Include="GamingSystem.cs" />
<Compile Include="User.cs" /> <Compile Include="User.cs" />
<Compile Include="UserGroup.cs" /> <Compile Include="UserGroup.cs" />
<Compile Include="Vote.cs" /> <Compile Include="Vote.cs" />
@ -84,7 +86,7 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Mappings\User.hbm.xml" /> <EmbeddedResource Include="Mappings\User.hbm.xml" />
<EmbeddedResource Include="Mappings\Publisher.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\Game.hbm.xml" />
<EmbeddedResource Include="Mappings\Quote.hbm.xml" /> <EmbeddedResource Include="Mappings\Quote.hbm.xml" />
</ItemGroup> </ItemGroup>
@ -94,6 +96,9 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Mappings\QuoteFlag.hbm.xml" /> <EmbeddedResource Include="Mappings\QuoteFlag.hbm.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Mappings\Category.hbm.xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. 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 Microsoft.Practices.Unity;
using Portoa.Web; using Portoa.Web;
using Portoa.Web.Unity; using Portoa.Web.Unity;
using UnityGenerics;
using VideoGameQuotes.Api; using VideoGameQuotes.Api;
using VideoGameQuotes.Api.Persistence; using VideoGameQuotes.Api.Persistence;
using VideoGameQuotes.Web.Controllers;
using VideoGameQuotes.Web.Security; using VideoGameQuotes.Web.Security;
using VideoGameQuotes.Web.Services;
namespace VideoGameQuotes.Web { namespace VideoGameQuotes.Web {
public class MvcApplication : ApplicationBase { public class MvcApplication : ApplicationBase {
@ -19,7 +22,9 @@ namespace VideoGameQuotes.Web {
Container Container
.AddNewExtension<LogAllMethodCalls>() .AddNewExtension<LogAllMethodCalls>()
.RegisterType<ICurrentUserProvider, SessionBasedUserProvider>() .RegisterType<ICurrentUserProvider, SessionBasedUserProvider>()
.RegisterType<IsValidUserAttribute>(new InjectionProperty<IsValidUserAttribute>(attr => attr.UserProvider))
.RegisterType<IUserService, UserService>() .RegisterType<IUserService, UserService>()
.RegisterType<IQuoteService, QuoteService>()
.RegisterType<IUserRepository, UserRepository>(); .RegisterType<IUserRepository, UserRepository>();
} }
@ -29,6 +34,8 @@ namespace VideoGameQuotes.Web {
routes.MapRoute("about", "about", new { controller = "Home", action = "About" }); routes.MapRoute("about", "about", new { controller = "Home", action = "About" });
routes.MapRoute("contact", "contact", new { controller = "Home", action = "Contact" }); 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 }); 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.Configuration" />
<Reference Include="System.Web.Services" /> <Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" /> <Reference Include="System.EnterpriseServices" />
<Reference Include="UnityGenerics">
<HintPath>..\..\Lib\UnityGenerics.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Controllers\HomeController.cs" /> <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"> <Compile Include="Default.aspx.cs">
<DependentUpon>Default.aspx</DependentUpon> <DependentUpon>Default.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType> <SubType>ASPXCodeBehind</SubType>
</Compile> </Compile>
<Compile Include="Models\ContactModel.cs" /> <Compile Include="Models\ContactModel.cs" />
<Compile Include="Models\QuoteSubmitModel.cs" />
<Compile Include="Security\SessionBasedUserProvider.cs" /> <Compile Include="Security\SessionBasedUserProvider.cs" />
<Compile Include="Global.asax.cs"> <Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon> <DependentUpon>Global.asax</DependentUpon>
@ -106,6 +113,8 @@
<Content Include="Views\Home\About.aspx" /> <Content Include="Views\Home\About.aspx" />
<Content Include="Views\Home\Contact.aspx" /> <Content Include="Views\Home\Contact.aspx" />
<Content Include="Views\Home\ContactSuccess.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\ExceptionView.ascx" />
<Content Include="Views\Shared\Forbidden.aspx" /> <Content Include="Views\Shared\Forbidden.aspx" />
<Content Include="Views\Shared\NotFound.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; padding: 2px;
line-height: 1.2em; line-height: 1.2em;
} }
fieldset {
border: 1px solid #999999;
padding: 5px;
}
legend {
font-weight: bold;
margin-left: 20px;
padding: 5px;
}
.inset { .inset {
margin-left: 20px; margin-left: 20px;
@ -80,14 +89,14 @@ p {
background-color: #FFCCCC; background-color: #FFCCCC;
} }
.contact-form textarea { .contact-form textarea {
width: 100%; width: 100%;
} }
.contact-form input[type="text"] { .contact-form input[type="text"] {
width: 300px; width: 300px;
} }
.contact-form { .contact-form {
width: 600px; width: 600px;
} }
#header { #header {
@ -123,6 +132,10 @@ p {
border-bottom: 2px solid #000000; border-bottom: 2px solid #000000;
} }
#create-game-form, #create-system-form {
display: none;
}
#footer { #footer {
text-align: center; text-align: center;
font-size: 75%; font-size: 75%;

View File

@ -1,4 +1,5 @@
using System; using System;
using NHibernate;
using NHibernate.Cfg; using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl; using NHibernate.Tool.hbm2ddl;
using NUnit.Framework; using NUnit.Framework;
@ -37,29 +38,40 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
tx.Commit(); tx.Commit();
} }
var nes = new System { Abbreviation = "NES", Name = "Nintendo Entertainment System", ReleaseDate = new DateTime(1985, 10, 18) }; CreateInitialData(session, admin);
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) };
var gb = new System { Abbreviation = "GB", Name = "Game Boy", ReleaseDate = new DateTime(1989, 7, 31) }; private static void CreateInitialData(ISession session, User creator) {
var gbc = new System { Abbreviation = "GBC", Name = "Game Boy Color", ReleaseDate = new DateTime(1998, 11, 18) }; #region systems
var gba = new System { Abbreviation = "GBA", Name = "Game Boy Advance", ReleaseDate = new DateTime(2001, 6, 11) }; var fds = new GamingSystem { Abbreviation = "FDS", Name = "Family Computer Disk System", ReleaseDate = new DateTime(1986, 2, 21) };
var nds = new System { Abbreviation = "NES", Name = "Nintendo Entertainment System", ReleaseDate = new DateTime(1985, 10, 18) }; var nes = new GamingSystem { 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) }; 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()) { using (var tx = session.BeginTransaction()) {
var repo = new NHibernateRepository<System>(session); var repo = new NHibernateRepository<GamingSystem>(session);
repo.Save(nes); repo.Save(nes);
repo.Save(fds);
repo.Save(snes); repo.Save(snes);
repo.Save(genny); repo.Save(genny);
repo.Save(ps); repo.Save(ps);
@ -77,9 +89,89 @@ namespace VideoGameQuotes.Api.Tests.NHibernate {
repo.Save(gba); repo.Save(gba);
repo.Save(nds); repo.Save(nds);
repo.Save(psp); repo.Save(psp);
repo.Save(arcade);
repo.Save(tgfx);
tx.Commit(); 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 FK5B40970FE5573E38
;
alter table game_system_map drop foreign key FK5B40970FD86811D9
; ;
@ -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 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 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 vote;
drop table if exists game; drop table if exists game;
drop table if exists game_system_map; 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; 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 game_quote;
drop table if exists quote_category_map;
drop table if exists system;
drop table if exists category;
create table vote ( create table vote (
vote_id INTEGER NOT NULL AUTO_INCREMENT, vote_id INTEGER NOT NULL AUTO_INCREMENT,
created DATETIME not null, created DATETIME not null,
@ -66,12 +84,12 @@ alter table game_quote drop foreign key fk_quote_game
create table game ( create table game (
game_id INTEGER NOT NULL AUTO_INCREMENT, 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, created DATETIME not null,
screenshot BLOB, screenshot BLOB,
game_region INTEGER not null, game_region INTEGER not null,
creator INTEGER not null, creator INTEGER not null,
publisher_id INTEGER,
primary key (game_id) primary key (game_id)
); );
@ -81,6 +99,12 @@ alter table game_quote drop foreign key fk_quote_game
primary key (game_id, system_id) 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 ( create table publisher (
publisher_id INTEGER NOT NULL AUTO_INCREMENT, publisher_id INTEGER NOT NULL AUTO_INCREMENT,
publisher_name TEXT not null, publisher_name TEXT not null,
@ -89,18 +113,10 @@ alter table game_quote drop foreign key fk_quote_game
primary key (publisher_id) 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 ( create table vgquote_user (
user_id INTEGER NOT NULL AUTO_INCREMENT, user_id INTEGER NOT NULL AUTO_INCREMENT,
username VARCHAR(50) not null unique, username VARCHAR(50),
ip_address VARCHAR(40),
created DATETIME not null, created DATETIME not null,
user_group INTEGER not null, user_group INTEGER not null,
user_password VARCHAR(100), user_password VARCHAR(100),
@ -128,6 +144,28 @@ alter table game_quote drop foreign key fk_quote_game
primary key (quote_id) 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 alter table vote
add index (voter_id), add index (voter_id),
add constraint fk_vote_user add constraint fk_vote_user
@ -146,15 +184,9 @@ alter table game_quote drop foreign key fk_quote_game
foreign key (creator) foreign key (creator)
references vgquote_user (user_id); 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 alter table game_system_map
add index (system_id), add index (system_id),
add constraint FK5B40970FD86811D9 add constraint FK5B40970FE5573E38
foreign key (system_id) foreign key (system_id)
references system (system_id); references system (system_id);
@ -164,6 +196,18 @@ alter table game_quote drop foreign key fk_quote_game
foreign key (game_id) foreign key (game_id)
references game (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 alter table quote_flag
add index (user_id), add index (user_id),
add constraint fk_flag_user add constraint fk_flag_user
@ -187,3 +231,15 @@ alter table game_quote drop foreign key fk_quote_game
add constraint fk_quote_game add constraint fk_quote_game
foreign key (game_id) foreign key (game_id)
references game (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);