adding games/publishers/systems inline, rather than all at once

This commit is contained in:
tmont 2011-02-22 09:39:59 +00:00
parent 1658795cbe
commit 8eec190bc6
16 changed files with 364 additions and 173 deletions

View File

@ -13,12 +13,12 @@
<many-to-one name="Creator" column="creator" not-null="true" foreign-key="fk_game_user"/>
<set access="nosetter.camelcase" name="Systems" table="game_system_map" cascade="save-update">
<set access="nosetter.camelcase" name="Systems" table="game_system_map">
<key column="game_id" />
<many-to-many class="VideoGameQuotes.Api.GamingSystem" column="system_id" />
</set>
<set access="nosetter.camelcase" name="Publishers" table="game_publisher_map" cascade="save-update">
<set access="nosetter.camelcase" name="Publishers" table="game_publisher_map">
<key column="game_id" />
<many-to-many class="VideoGameQuotes.Api.Publisher" column="publisher_id" />
</set>

View File

@ -6,8 +6,8 @@
<generator class="identity" />
</id>
<property name="Name" column="system_name" not-null="true" length="255"/>
<property name="Abbreviation" column="system_abbreviation" not-null="false" length="12"/>
<property name="Name" column="system_name" not-null="true" length="255" unique="true"/>
<property name="Abbreviation" column="system_abbreviation" not-null="false" length="12" unique="true"/>
<property name="Created" column="created" not-null="true" />
<property name="ReleaseDate" column="release_date" not-null="false" />
</class>

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using JetBrains.Annotations;
using Portoa.Persistence;
using Portoa.Validation.DataAnnotations;
using Portoa.Web;
@ -173,7 +172,7 @@ namespace VideoGameQuotes.Web.Controllers {
? quoteService.GetQuote(model.QuoteId)
: new Quote {Creator = currentUserProvider.CurrentUser};
quote.Game = GetGameFromModelData(model);
quote.Game = quoteService.GetGame(model.GameId);
quote.Text = model.QuoteText;
if (model.CategoryIds != null && model.CategoryIds.Count > 0) {
@ -198,71 +197,6 @@ namespace VideoGameQuotes.Web.Controllers {
}
}
[CanBeNull]
private Game GetGameFromModelData(EditQuoteModel 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,
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 ResetEditQuoteModel(EditQuoteModel model) {
model.AllGames = quoteService.GetAllGames().OrderBy(game => game.Name);
model.AllSystems = quoteService.GetAllSystems().OrderBy(system => system.ReleaseDate);

View File

@ -0,0 +1,87 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Portoa.Util;
using Portoa.Web;
using Portoa.Web.Controllers;
using VideoGameQuotes.Api;
using VideoGameQuotes.Web.Models;
using VideoGameQuotes.Web.Security;
using VideoGameQuotes.Web.Services;
namespace VideoGameQuotes.Web.Controllers {
public class GameController : Controller {
private readonly IGameService gameService;
private readonly ICurrentUserProvider<User> userProvider;
public GameController(IGameService gameService, ICurrentUserProvider<User> userProvider) {
this.gameService = gameService;
this.userProvider = userProvider;
}
[HttpPost, VerifyUser]
public ActionResult Create(CreateGameModel model) {
if (!ModelState.IsValid) {
return Json(this.CreateJsonErrorResponse("Invalid request"));
}
if (gameService.FindByNameAndSystems(model.Name, model.SystemIds) != null) {
return Json(this.CreateJsonResponse("A game with that name for one of those systems already exists"));
}
var game = new Game { Name = model.Name, Website = model.Website, Region = model.Region, Creator = userProvider.CurrentUser };
model.SystemIds.Walk(id => game.AddSystem(new GamingSystem { Id = id }));
if (model.PublisherIds != null) {
model.PublisherIds.Walk(id => game.AddPublisher(new Publisher {Id = id}));
}
game = gameService.Save(game);
return Json(this.CreateJsonResponse(data: game.ToDto()));
}
}
public class PublisherController : Controller {
private readonly IPublisherService publisherService;
public PublisherController(IPublisherService publisherService) {
this.publisherService = publisherService;
}
[HttpPost, VerifyUser]
public ActionResult Create(CreatePublisherModel model) {
if (!ModelState.IsValid) {
return Json(this.CreateJsonErrorResponse("Invalid request"));
}
if (publisherService.FindByName(model.Name) != null) {
return Json(this.CreateJsonResponse("A publisher with that name already exists"));
}
var publisher = publisherService.Save(new Publisher { Name = model.Name, Website = model.Website });
return Json(this.CreateJsonResponse(data: publisher.ToDto()));
}
}
public class SystemController : Controller {
private readonly ISystemService systemService;
public SystemController(ISystemService systemService) {
this.systemService = systemService;
}
[HttpPost, VerifyUser]
public ActionResult Create(CreateSystemModel model) {
if (!ModelState.IsValid) {
return Json(this.CreateJsonErrorResponse("Invalid request"));
}
if (systemService.FindByNameOrAbbreviation(model.Name, model.Abbreviation).Any()) {
return Json(this.CreateJsonResponse("A system with that name or abbreviation already exists"));
}
var system = systemService.Save(new GamingSystem { Abbreviation = model.Abbreviation, Name = model.Name, ReleaseDate = model.ReleaseDate });
return Json(this.CreateJsonResponse(data: system.ToDto()));
}
}
}

View File

@ -42,6 +42,9 @@ namespace VideoGameQuotes.Web {
.RegisterType<IUserService, UserService>()
.RegisterType<IAdministrationService, AdministrationService>()
.RegisterType<IQuoteService, QuoteService>()
.RegisterType<ISystemService, SystemService>()
.RegisterType<IPublisherService, PublisherService>()
.RegisterType<IGameService, GameService>()
.RegisterType<IApiService, ApiService>()
.RegisterType<IAuthenticationService, FormsAuthenticationService>()
.RegisterType<IQuoteSearcher, LuceneQuoteSearcher>()
@ -68,6 +71,8 @@ namespace VideoGameQuotes.Web {
//bullshit route so that RenderAction works
routes.MapRoute("mainmenu", "home/mainmenu", new { controller = "Home", action = "MainMenu" });
routes.MapRoute("crud-default", "{controller}/{action}", null, new { controller = "system|publisher|game", action = "create" });
routes.MapRoute("users-paged", "admin/users/{start}-{end}", new { controller = "Admin", action = "Users" }, new { start = @"\d+", end = @"\d+" });
routes.MapRoute("admin", "admin/{action}", new { controller = "Admin", action = "Index" }, new { action = "users|create|flags|password" });

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Models {
public class CreateGameModel {
[Required]
public string Name { get; set; }
public string Website { get; set; }
public Region Region { get; set; }
[Required]
public List<int> PublisherIds { get; set; }
public List<int> SystemIds { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace VideoGameQuotes.Web.Models {
public class CreatePublisherModel {
public string Name { get; set; }
public string Website { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace VideoGameQuotes.Web.Models {
public class CreateSystemModel {
[Required]
public string Name { get; set; }
[Required, StringLength(12)]
public string Abbreviation { get; set; }
[Required]
public DateTime ReleaseDate { get; set; }
}
}

View File

@ -20,8 +20,6 @@ namespace VideoGameQuotes.Web.Models {
QuoteText = quote.Text;
CategoryIds = quote.Categories.Select(category => category.Id).ToList();
GameId = quote.Game.Id;
PublisherIds = quote.Game.Publishers.Select(publisher => publisher.Id).ToList();
SystemIds = quote.Game.Systems.Select(system => system.Id).ToList();
ActionName = "Edit";
}
@ -38,40 +36,13 @@ namespace VideoGameQuotes.Web.Models {
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 Region 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<Category> AllCategories { 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 }));
return AllGames.Select(game => new SelectListItem { Value = game.Id.ToString(), Text = game.Name });
}
private static string MakeTable<T>(string tableId, int cellsPerRow, IEnumerable<T> items, Func<T, string> cellDataCallback) {

View File

@ -2,12 +2,6 @@
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Models {
public class PagedUserModel {
public int Start { get; set; }
public int End { get; set; }
}
public class QuoteModel {
[NotNull]
public Quote Quote { get; set; }

View File

@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Portoa.Persistence;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Services {
public interface IGameService {
[CanBeNull]
Game FindByNameAndSystems(string name, IEnumerable<int> systemIds);
Game Save(Game game);
}
public class GameService : IGameService {
private readonly IRepository<Game> repository;
public GameService(IRepository<Game> repository) {
this.repository = repository;
}
[UnitOfWork]
public Game FindByNameAndSystems(string name, IEnumerable<int> systemIds) {
return repository
.Records
.FirstOrDefault(game => game.Name == name && game.Systems.Any(system => systemIds.Contains(system.Id)));
}
[UnitOfWork]
public Game Save(Game game) {
return repository.Save(game);
}
}
}

View File

@ -0,0 +1,31 @@
using System.Linq;
using JetBrains.Annotations;
using Portoa.Persistence;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Services {
public interface IPublisherService {
[CanBeNull]
Publisher FindByName(string name);
Publisher Save(Publisher publisher);
}
public class PublisherService : IPublisherService {
private readonly IRepository<Publisher> repository;
public PublisherService(IRepository<Publisher> repository) {
this.repository = repository;
}
[UnitOfWork]
public Publisher FindByName(string name) {
return repository.Records.FirstOrDefault(publisher => publisher.Name == name);
}
[UnitOfWork]
public Publisher Save(Publisher publisher) {
return repository.Save(publisher);
}
}
}

View File

@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using Portoa.Persistence;
using VideoGameQuotes.Api;
namespace VideoGameQuotes.Web.Services {
public interface ISystemService {
IEnumerable<GamingSystem> FindByNameOrAbbreviation(string name, string abbreviation);
GamingSystem Save(GamingSystem system);
}
public class SystemService : ISystemService {
private readonly IRepository<GamingSystem> repository;
public SystemService(IRepository<GamingSystem> repository) {
this.repository = repository;
}
[UnitOfWork]
public IEnumerable<GamingSystem> FindByNameOrAbbreviation(string name, string abbreviation) {
return repository
.Records
.Where(system => system.Abbreviation == abbreviation || system.Name == name);
}
[UnitOfWork]
public GamingSystem Save(GamingSystem system) {
return repository.Save(system);
}
}
}

View File

@ -87,12 +87,19 @@
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\ApiController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\SystemController.cs" />
<Compile Include="Models\CreateGameModel.cs" />
<Compile Include="Models\CreatePublisherModel.cs" />
<Compile Include="Services\GameService.cs" />
<Compile Include="Services\PublisherService.cs" />
<Compile Include="Services\SystemService.cs" />
<Compile Include="Controllers\UserController.cs" />
<Compile Include="Models\ApiModel.cs" />
<Compile Include="Models\BrowseModel.cs" />
<Compile Include="Models\BrowseModelBinder.cs" />
<Compile Include="Models\ChangePasswordModel.cs" />
<Compile Include="Models\CreateAdminModel.cs" />
<Compile Include="Models\CreateSystemModel.cs" />
<Compile Include="Models\InvalidUsernameModel.cs" />
<Compile Include="Models\MainMenuModel.cs" />
<Compile Include="Models\QualifiedBrowseModel.cs" />

View File

@ -5,12 +5,10 @@
<% using (Html.BeginForm(Model.ActionName, Model.ControllerName)) { %>
<%= Html.HiddenFor(model => model.QuoteId, new { id = "quote-id" })%>
<p>
<span id="game-select">
<%= Html.Label("Game", "GameId") %>
<br />
<%= Html.DropDownListFor(model => model.GameId, Model.GetGameList()) %>
</span>
<p id="game-select">
<%= Html.Label("Game", "GameId") %>
<br />
<%= Html.DropDownListFor(model => model.GameId, Model.GetGameList()) %>
<a href="#" id="create-game-link">Create new game</a>
</p>
@ -20,82 +18,87 @@
<legend>Create new game</legend>
<p>
<%= Html.LabelFor(model => model.GameName) %>
<%= Html.Label("Name", "GameName") %>
<br />
<%= Html.TextBoxFor(model => model.GameName) %>
<%= Html.TextBox("GameName") %>
</p>
<p>
<%= Html.LabelFor(model => model.GameWebsite) %> <small>(link to Wikipedia page or something)</small>
<%= Html.Label("Website", "GameWebsite") %> <small>(link to Wikipedia page or something)</small>
<br />
<%= Html.TextBoxFor(model => model.GameWebsite) %>
<%= Html.TextBox("GameWebsite") %>
</p>
<p>
<%= Html.LabelFor(model => model.GameRegions) %>
Regions
<br />
<%= Model.MakeRegionTable() %>
</p>
<p>
<span id="system-select">
<%= Html.LabelFor(model => model.SystemIds) %>
<br />
<%= Model.MakeSystemTable(Html) %>
</span>
<div id="system-select">
Systems
<br />
<%= Model.MakeSystemTable(Html) %>
<a href="#" id="create-system-link">Create new system</a>
</p>
</div>
<div id="create-system-form">
<fieldset>
<legend>Create new system</legend>
<p>
<%= Html.LabelFor(model => model.SystemName) %>
<%= Html.Label("Name", "SystemName") %>
<br />
<%= Html.TextBoxFor(model => model.SystemName) %>
<%= Html.TextBox("SystemName") %>
</p>
<p>
<%= Html.LabelFor(model => model.SystemAbbreviation) %>
<%= Html.Label("Abbreviation", "SystemAbbreviation") %>
<br />
<%= Html.TextBoxFor(model => model.SystemAbbreviation) %>
<%= Html.TextBox("SystemAbbreviation")%>
</p>
<p>
<%= Html.LabelFor(model => model.SystemReleaseDate) %>
<%= Html.Label("Release Date", "SystemReleaseDate") %>
<br />
<%= Html.TextBox("SystemReleaseDate", DateTime.UtcNow.ToString("yyyy-MM-dd")) %>
<%= Html.TextBox("SystemReleaseDate", null) %>
</p>
<%= Html.Button("Create System", new { id = "create-system-submit" })%>
<%= Html.Button("Cancel", new { id = "create-system-cancel" })%>
</fieldset>
</div>
<p>
<span id="publisher-select">
<%= Html.LabelFor(model => model.PublisherIds) %>
<br />
<%= Model.MakePublisherTable(Html) %>
</span>
<div id="publisher-select">
Publishers
<br />
<%= Model.MakePublisherTable(Html) %>
<a href="#" id="create-publisher-link">Create new publisher</a>
</p>
</div>
<div id="create-publisher-form">
<fieldset>
<legend>Create new publisher</legend>
<p>
<%= Html.LabelFor(model => model.PublisherName) %>
<%= Html.Label("Name", "PublisherName") %>
<br />
<%= Html.TextBoxFor(model => model.PublisherName) %>
<%= Html.TextBox("PublisherName") %>
</p>
<p>
<%= Html.LabelFor(model => model.PublisherWebsite) %>
<%= Html.Label("Website", "PublisherWebsite") %>
<br />
<%= Html.TextBoxFor(model => model.PublisherWebsite) %>
<%= Html.TextBox("PublisherWebsite") %>
</p>
<%= Html.Button("Create Publisher", new { id = "create-publisher-submit" })%>
<%= Html.Button("Cancel", new { id = "create-publisher-cancel" })%>
</fieldset>
</div>
<%= Html.Button("Create Game", new { id = "create-game-submit" })%>
<%= Html.Button("Cancel", new { id = "create-game-cancel" })%>
</fieldset>
</div>

View File

@ -225,43 +225,104 @@
};
var setupQuoteForm = function() {
$("#create-game-link").click(function() {
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");
var toggleFormAndLink = function(type) {
return function() {
$("#create-" + type + "-form").toggle();
$("#" + type + "-select").toggle();
return false;
}
};
var addNewCheckbox = function($table, name, value, text, cellsPerRow) {
var $row = $table.find("tr:last");
if ($row.find("td").length === cellsPerRow) {
$row = $("<tr/>");
$table.append($row);
}
$form.toggle();
$("#game-select").toggle();
var $cell = $("<td/>").append($("<input/>").attr({
type: "checkbox",
name: name,
value: value,
id: name + "_" + value,
checked: "checked"
})).append($("<label/>").attr("for", name + "_" + value).text(text));
$row.append($cell);
$table.append($row);
};
$("#create-game-link, #create-game-cancel").click(toggleFormAndLink("game"));
$("#create-system-link, #create-system-cancel").click(toggleFormAndLink("system"));
$("#create-publisher-link, #create-publisher-cancel").click(toggleFormAndLink("publisher"));
$("#create-system-submit").click(function() {
$.ajax("/system/create", {
type: "POST",
data: { Name: $("#SystemName").val(), Abbreviation: $("#SystemAbbreviation").val(), ReleaseDate: $("#SystemReleaseDate").val() },
success: function(data, statux, $xhr) {
if (data.Error !== null) {
alert(data.Error);
return;
}
//add checkbox to table
addNewCheckbox($("#system-checkbox-table"), "SystemIds", data.Data.Id, data.Data.Abbreviation, 8);
toggleFormAndLink("system")();
}
});
return false;
});
$("#create-system-link").click(function() {
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();
$("#create-publisher-submit").click(function() {
$.ajax("/publisher/create", {
type: "POST",
data: { Name: $("#PublisherName").val(), Website: $("#PublisherWebsite").val() },
success: function(data, statux, $xhr) {
if (data.Error !== null) {
alert(data.Error);
return;
}
addNewCheckbox($("#publisher-checkbox-table"), "PublisherIds", data.Data.Id, data.Data.Name, 8);
toggleFormAndLink("publisher")();
}
});
return false;
});
$("#create-publisher-link").click(function() {
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();
$("#create-game-submit").click(function() {
var regions = [], publishers = [], systems = [];
$("input:checked[name='GameRegions']").each(function(index, input) { regions.push(input.value); });
$("input:checked[name='SystemIds']").each(function(index, input) { systems.push(input.value); });
$("input:checked[name='PublisherIds']").each(function(index, input) { publishers.push(input.value); });
$.ajax("/game/create", {
type: "POST",
data: {
Name: $("#GameName").val(),
Website: $("#GameWebsite").val(),
Region: regions,
SystemIds: systems,
PublisherIds: publishers
},
traditional: true,
success: function(data, statux, $xhr) {
if (data.Error !== null) {
alert(data.Error);
return;
}
$("#GameId")
.append($("<option/>").attr({ value: data.Data.Id}).text(data.Data.Name))
.val(data.Data.Id);
toggleFormAndLink("game")();
}
});
return false;
});