* edit/create/delete categories
* also made error views user-aware
This commit is contained in:
parent
dc9a415428
commit
ff3499b3b9
78
Src/VideoGameQuotes.Web/Controllers/CategoryController.cs
Normal file
78
Src/VideoGameQuotes.Web/Controllers/CategoryController.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System.Web.Mvc;
|
||||
using Portoa.Persistence;
|
||||
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 CategoryController : Controller {
|
||||
private readonly ICategoryService categoryService;
|
||||
|
||||
public CategoryController(ICategoryService categoryService) {
|
||||
this.categoryService = categoryService;
|
||||
}
|
||||
|
||||
[HttpPost, VerifyUser(Group = UserGroup.Admin)]
|
||||
public JsonResult Delete(int id) {
|
||||
if (id < 1) {
|
||||
return Json(this.CreateJsonResponse("Invalid ID"));
|
||||
}
|
||||
|
||||
try {
|
||||
var category = categoryService.FindById(id);
|
||||
var numQuotes = categoryService.GetQuotesForCategory(category);
|
||||
if (numQuotes > 0) {
|
||||
return Json(this.CreateJsonErrorResponse(
|
||||
string.Format("There are {0} quotes that are still using this category", numQuotes)
|
||||
));
|
||||
}
|
||||
} catch (EntityNotFoundException) {
|
||||
return Json(this.CreateJsonErrorResponse("No category exists for ID " + id));
|
||||
}
|
||||
|
||||
categoryService.Delete(id);
|
||||
return Json(this.CreateJsonResponse());
|
||||
}
|
||||
|
||||
[HttpPost, VerifyUser(Group = UserGroup.Admin)]
|
||||
public JsonResult Edit(EditCategoryModel model) {
|
||||
if (model.CategoryId < 1) {
|
||||
ModelState.AddModelError("CategoryId", "Invalid category ID");
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
return Json(this.CreateJsonErrorResponse("Some errors occurred"));
|
||||
}
|
||||
|
||||
try {
|
||||
var category = categoryService.FindById(model.CategoryId);
|
||||
if (categoryService.FindByName(model.CategoryName) != null) {
|
||||
return Json(this.CreateJsonErrorResponse("A category already exists for that name"));
|
||||
}
|
||||
|
||||
category.Name = model.CategoryName;
|
||||
|
||||
category = categoryService.Save(category);
|
||||
return Json(this.CreateJsonResponse(data: category.ToDto()));
|
||||
} catch (EntityNotFoundException) {
|
||||
return Json(this.CreateJsonErrorResponse("No category exists for ID " + model.CategoryId));
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost, VerifyUser]
|
||||
public JsonResult Create(EditCategoryModel model) {
|
||||
if (!ModelState.IsValid) {
|
||||
return Json(this.CreateJsonErrorResponse("Some errors occurred."));
|
||||
}
|
||||
|
||||
if (categoryService.FindByName(model.CategoryName) != null) {
|
||||
return Json(this.CreateJsonErrorResponse("A category already exists for that name"));
|
||||
}
|
||||
|
||||
var category = categoryService.Save(new Category { Name = model.CategoryName });
|
||||
return Json(this.CreateJsonResponse(data: category.ToDto()));
|
||||
}
|
||||
}
|
||||
}
|
@ -233,17 +233,6 @@ namespace VideoGameQuotes.Web.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost, VerifyUser]
|
||||
public JsonResult CreateCategory(Category category) {
|
||||
try {
|
||||
category = quoteService.SaveCategory(category);
|
||||
var data = new Dictionary<string, string> { { "categoryId", category.Id.ToString() }, { "categoryName", category.Name } };
|
||||
return Json(this.CreateJsonResponse(null, data));
|
||||
} catch (Exception e) {
|
||||
return Json(this.CreateJsonErrorResponse(e));
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult Search(string searchQuery) {
|
||||
var model = new SearchModel {
|
||||
User = currentUserProvider.CurrentUser,
|
||||
|
@ -43,6 +43,7 @@ namespace VideoGameQuotes.Web {
|
||||
.RegisterType<IAdministrationService, AdministrationService>()
|
||||
.RegisterType<IQuoteService, QuoteService>()
|
||||
.RegisterType<ISystemService, SystemService>()
|
||||
.RegisterType<ICategoryService, CategoryService>()
|
||||
.RegisterType<IPublisherService, PublisherService>()
|
||||
.RegisterType<IGameService, GameService>()
|
||||
.RegisterType<IApiService, ApiService>()
|
||||
@ -71,7 +72,7 @@ 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|edit|delete" });
|
||||
routes.MapRoute("crud-default", "{controller}/{action}", null, new { controller = "system|publisher|game|category", action = "create|edit|delete" });
|
||||
|
||||
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" });
|
||||
@ -88,7 +89,6 @@ namespace VideoGameQuotes.Web {
|
||||
routes.MapRoute("quote", "{action}", new { controller = "Quote" }, new { action = "submit|recent|random|vote|report" });
|
||||
routes.MapRoute("dismiss-flag", "dismiss-flag", new { controller = "Quote", action = "DismissFlag" });
|
||||
routes.MapRoute("individual-quote", "quote/{id}/{*text}", new { controller = "Quote", action = "Quote" }, new { id = @"\d+" });
|
||||
routes.MapRoute("create-category", "category/create", new { controller = "Quote", action = "CreateCategory" });
|
||||
routes.MapRoute("default", "{controller}", new { controller = "home", action = "index" });
|
||||
}
|
||||
}
|
||||
|
9
Src/VideoGameQuotes.Web/Models/EditCategoryModel.cs
Normal file
9
Src/VideoGameQuotes.Web/Models/EditCategoryModel.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace VideoGameQuotes.Web.Models {
|
||||
public class EditCategoryModel {
|
||||
public int CategoryId { get; set; }
|
||||
[Required(ErrorMessage = "The category must have a name, queerball")]
|
||||
public string CategoryName { get; set; }
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ namespace VideoGameQuotes.Web.Security {
|
||||
if (!allowedToExecuteAction) {
|
||||
filterContext.Result = new ErrorViewResult {
|
||||
Message = "You are not a verified user (are you hiding your IP address?)",
|
||||
ModelCreator = exception => new ErrorModel<User> { Exception = exception, User = UserProvider.CurrentUser },
|
||||
StatusCode = HttpStatusCode.Forbidden,
|
||||
ViewName = "Forbidden"
|
||||
};
|
||||
|
53
Src/VideoGameQuotes.Web/Services/CategoryService.cs
Normal file
53
Src/VideoGameQuotes.Web/Services/CategoryService.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Portoa.Persistence;
|
||||
using VideoGameQuotes.Api;
|
||||
|
||||
namespace VideoGameQuotes.Web.Services {
|
||||
public interface ICategoryService {
|
||||
[CanBeNull]
|
||||
Category FindByName(string name);
|
||||
Category Save(Category category);
|
||||
Category FindById(int id);
|
||||
void Delete(int id);
|
||||
int GetQuotesForCategory(Category category);
|
||||
}
|
||||
|
||||
public class CategoryService : ICategoryService {
|
||||
private readonly IRepository<Category> categoryRepository;
|
||||
private readonly IRepository<Quote> quoteRepository;
|
||||
|
||||
public CategoryService(IRepository<Category> categoryRepository, IRepository<Quote> quoteRepository) {
|
||||
this.categoryRepository = categoryRepository;
|
||||
this.quoteRepository = quoteRepository;
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public Category FindByName(string name) {
|
||||
return categoryRepository.Records.FirstOrDefault(category => category.Name == name);
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public Category Save(Category category) {
|
||||
return categoryRepository.Save(category);
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public Category FindById(int id) {
|
||||
return categoryRepository.FindById(id);
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public void Delete(int id) {
|
||||
categoryRepository.Delete(id);
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public int GetQuotesForCategory(Category category) {
|
||||
return quoteRepository
|
||||
.Records
|
||||
.Where(quote => quote.Categories.Contains(category))
|
||||
.Count();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Portoa.Persistence;
|
||||
|
@ -86,12 +86,15 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Controllers\ApiController.cs" />
|
||||
<Compile Include="Controllers\CategoryController.cs" />
|
||||
<Compile Include="Controllers\GameController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\PublisherController.cs" />
|
||||
<Compile Include="Controllers\SystemController.cs" />
|
||||
<Compile Include="Models\EditCategoryModel.cs" />
|
||||
<Compile Include="Models\EditGameModel.cs" />
|
||||
<Compile Include="Models\EditPublisherModel.cs" />
|
||||
<Compile Include="Services\CategoryService.cs" />
|
||||
<Compile Include="Services\GameService.cs" />
|
||||
<Compile Include="Services\PublisherService.cs" />
|
||||
<Compile Include="Services\SystemService.cs" />
|
||||
@ -140,7 +143,9 @@
|
||||
<Content Include="media\css\global.css" />
|
||||
<Content Include="media\css\quote.css" />
|
||||
<Content Include="media\css\reset.css" />
|
||||
<Content Include="media\images\accept.png" />
|
||||
<Content Include="media\images\add.png" />
|
||||
<Content Include="media\images\cancel.png" />
|
||||
<Content Include="media\images\delete.png" />
|
||||
<Content Include="media\images\favicon.png" />
|
||||
<Content Include="media\images\loading.gif" />
|
||||
|
@ -1,12 +1,15 @@
|
||||
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Portoa.Web.ErrorHandling.ErrorModel>" %>
|
||||
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Portoa.Web.ErrorHandling.ErrorModel<VideoGameQuotes.Api.User>>" %>
|
||||
<%@ Import Namespace="VideoGameQuotes.Api" %>
|
||||
|
||||
<%
|
||||
if (true) {
|
||||
if (Model.Exception != null) { %>
|
||||
<h2>Exception Details</h2> <%
|
||||
Html.RenderPartial("RecursiveExceptionView", Model.Exception);
|
||||
} else { %>
|
||||
<p class="info">No exception was thrown.</p>
|
||||
<% }
|
||||
if (Model.User == null || Model.User.Group < UserGroup.Admin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Model.Exception != null) { %>
|
||||
<h2>Exception Details</h2> <%
|
||||
Html.RenderPartial("RecursiveExceptionView", Model.Exception);
|
||||
} else { %>
|
||||
<p class="info">No exception was thrown.</p>
|
||||
<% }
|
||||
%>
|
@ -1,4 +1,4 @@
|
||||
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Portoa.Web.ErrorHandling.ErrorModel>" MasterPageFile="~/Views/Shared/Site.Master" %>
|
||||
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Portoa.Web.ErrorHandling.ErrorModel<VideoGameQuotes.Api.User>>" MasterPageFile="~/Views/Shared/Site.Master" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">Forbidden</asp:Content>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Portoa.Web.ErrorHandling.ErrorModel>" MasterPageFile="~/Views/Shared/Site.Master" %>
|
||||
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Portoa.Web.ErrorHandling.ErrorModel<VideoGameQuotes.Api.User>>" MasterPageFile="~/Views/Shared/Site.Master" %>
|
||||
|
||||
<asp:Content ContentPlaceHolderID="TitleContent" runat="server">404</asp:Content>
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Exception>" %>
|
||||
<%@ Import Namespace="Portoa.Util" %>
|
||||
|
||||
<p class="exception-message"><%= Model.GetType().GetFriendlyName(false) %>: <code style="white-space: pre"><%= Html.Encode(Model.Message) %></code></p>
|
||||
<p class="exception-message"><%= Model.GetType().GetFriendlyName(false) %>: <code style="white-space: pre"><%: Model.Message %></code></p>
|
||||
|
||||
<pre><%= Model.StackTrace %></pre>
|
||||
<pre><%: Model.StackTrace %></pre>
|
||||
|
||||
<hr />
|
||||
|
||||
|
BIN
Src/VideoGameQuotes.Web/media/images/accept.png
Normal file
BIN
Src/VideoGameQuotes.Web/media/images/accept.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 781 B |
BIN
Src/VideoGameQuotes.Web/media/images/cancel.png
Normal file
BIN
Src/VideoGameQuotes.Web/media/images/cancel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 587 B |
Loading…
Reference in New Issue
Block a user