* improved default browse page
* fixed bug where you couldn't add more categories if none already existed * added ability to delete quotes * added call handler to delete the search index when a quote is deleted
This commit is contained in:
		
							parent
							
								
									2ac8d0155b
								
							
						
					
					
						commit
						a41335c5ba
					
				| @ -0,0 +1,31 @@ | |||||||
|  | using Microsoft.Practices.Unity; | ||||||
|  | using Microsoft.Practices.Unity.InterceptionExtension; | ||||||
|  | using Portoa.Search; | ||||||
|  | using VideoGameQuotes.Api; | ||||||
|  | 
 | ||||||
|  | namespace VideoGameQuotes.Web.Configuration { | ||||||
|  | 	/// <summary> | ||||||
|  | 	/// Call handler that deletes the search index whenever a quote is deleted | ||||||
|  | 	/// </summary> | ||||||
|  | 	public class DeleteSearchIndexCallHandler : ICallHandler { | ||||||
|  | 		private readonly IUnityContainer container; | ||||||
|  | 
 | ||||||
|  | 		public DeleteSearchIndexCallHandler(IUnityContainer container) { | ||||||
|  | 			this.container = container; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { | ||||||
|  | 			var quoteId = (int)input.Arguments[0]; | ||||||
|  | 			var returnValue = getNext()(input, getNext); | ||||||
|  | 			if (returnValue.Exception != null) { | ||||||
|  | 				return returnValue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			container.Resolve<ISearchIndexBuilder<Quote, int>>().DeleteIndex(new Quote { Id = quoteId }); | ||||||
|  | 
 | ||||||
|  | 			return returnValue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public int Order { get; set; } | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -43,6 +43,12 @@ namespace VideoGameQuotes.Web.Configuration { | |||||||
| 				.AddPolicy("UpdateSearchIndexPolicy") | 				.AddPolicy("UpdateSearchIndexPolicy") | ||||||
| 				.AddCallHandler<UpdateSearchIndexCallHandler>() | 				.AddCallHandler<UpdateSearchIndexCallHandler>() | ||||||
| 				.AddMatchingRule(new QuoteUpdatedMatchingRule()); | 				.AddMatchingRule(new QuoteUpdatedMatchingRule()); | ||||||
|  | 
 | ||||||
|  | 			Container | ||||||
|  | 				.Configure<Interception>() | ||||||
|  | 				.AddPolicy("DeleteSearchIndexPolicy") | ||||||
|  | 				.AddCallHandler<DeleteSearchIndexCallHandler>() | ||||||
|  | 				.AddMatchingRule(new QuoteDeletedMatchingRule()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		#region lucene-related factories | 		#region lucene-related factories | ||||||
| @ -60,6 +66,7 @@ namespace VideoGameQuotes.Web.Configuration { | |||||||
| 		} | 		} | ||||||
| 		#endregion | 		#endregion | ||||||
| 
 | 
 | ||||||
|  | 		#region matching rules | ||||||
| 		private class QuoteUpdatedMatchingRule : IMatchingRule { | 		private class QuoteUpdatedMatchingRule : IMatchingRule { | ||||||
| 			private static readonly MethodBase saveMethod = typeof(IRepository<Quote, int>).GetMethod("Save", new[] { typeof(Quote) }); | 			private static readonly MethodBase saveMethod = typeof(IRepository<Quote, int>).GetMethod("Save", new[] { typeof(Quote) }); | ||||||
| 
 | 
 | ||||||
| @ -67,5 +74,14 @@ namespace VideoGameQuotes.Web.Configuration { | |||||||
| 				return member == saveMethod; | 				return member == saveMethod; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		private class QuoteDeletedMatchingRule : IMatchingRule { | ||||||
|  | 			private static readonly MethodBase deleteMethod = typeof(IRepository<Quote, int>).GetMethod("Delete", new[] { typeof(int) }); | ||||||
|  | 
 | ||||||
|  | 			public bool Matches(MethodBase member) { | ||||||
|  | 				return member == deleteMethod; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		#endregion | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -31,13 +31,23 @@ namespace VideoGameQuotes.Web.Controllers { | |||||||
| 			return this.SerializeToJson(data); | 			return this.SerializeToJson(data); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		[HttpPost, VerifyUser(Group = UserGroup.Admin)] | ||||||
|  | 		public ActionResult Delete(int id) { | ||||||
|  | 			try { | ||||||
|  | 				quoteService.Delete(id); | ||||||
|  | 				return Json(this.CreateJsonResponse()); | ||||||
|  | 			} catch (Exception e) { | ||||||
|  | 				return Json(this.CreateJsonErrorResponse(e)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		public ActionResult Browse(BrowseModel model, int page = 1) { | 		public ActionResult Browse(BrowseModel model, int page = 1) { | ||||||
| 			if (page < 1) { | 			if (page < 1) { | ||||||
| 				return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; | 				return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (model.IsEmpty) { | 			if (model.IsEmpty) { | ||||||
| 				return View("DefaultBrowse"); | 				return View("DefaultBrowse", quoteService.GetDefaultBrowseModel()); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			model.CurrentUser = currentUserProvider.CurrentUser; | 			model.CurrentUser = currentUserProvider.CurrentUser; | ||||||
|  | |||||||
| @ -75,7 +75,8 @@ namespace VideoGameQuotes.Web { | |||||||
| 
 | 
 | ||||||
| 			//these routes don't work with constraints in mono...? | 			//these routes don't work with constraints in mono...? | ||||||
| 			routes.MapSmartRoute("quote-edit", "quote/edit/{id}", new { controller = "Quote", action = "Edit" }); | 			routes.MapSmartRoute("quote-edit", "quote/edit/{id}", new { controller = "Quote", action = "Edit" }); | ||||||
| 			routes.MapSmartRoute("individual-quote-with-text", "quote/{id}/{*text}", new { controller = "Quote", action = "Quote" }); | 			routes.MapSmartRoute("quote-delete", "quote/delete", new { controller = "Quote", action = "Delete" }); | ||||||
|  | 			routes.MapSmartRoute("single-quote", "quote/{id}/{*text}", new { controller = "Quote", action = "Quote" }); | ||||||
| 
 | 
 | ||||||
| 			routes.MapSmartRoute("dismiss-flag", "dismiss-flag", new { controller = "Quote", action = "DismissFlag" }); | 			routes.MapSmartRoute("dismiss-flag", "dismiss-flag", new { controller = "Quote", action = "DismissFlag" }); | ||||||
| 			routes.MapSmartRoute("default", "", new { controller = "Home", action = "Index" }); | 			routes.MapSmartRoute("default", "", new { controller = "Home", action = "Index" }); | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								Src/VideoGameQuotes.Web/Models/DefaultBrowseModel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Src/VideoGameQuotes.Web/Models/DefaultBrowseModel.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | namespace VideoGameQuotes.Web.Models { | ||||||
|  | 	public class DefaultBrowseModel { | ||||||
|  | 		public int TotalNumberOfQuotes { get; set; } | ||||||
|  | 		public int TotalNumberOfGames { get; set; } | ||||||
|  | 		public int TotalNumberOfSystems { get; set; } | ||||||
|  | 		public int TotalNumberOfPublishers { get; set; } | ||||||
|  | 		public int TotalNumberOfCategories { get; set; } | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -25,6 +25,8 @@ namespace VideoGameQuotes.Web.Services { | |||||||
| 		Vote GetVoteOrCreateNew(Quote quote, User voter); | 		Vote GetVoteOrCreateNew(Quote quote, User voter); | ||||||
| 		IEnumerable<Quote> GetBrowsableQuotes(BrowseModel model, int start, int end, out int totalCount); | 		IEnumerable<Quote> GetBrowsableQuotes(BrowseModel model, int start, int end, out int totalCount); | ||||||
| 		Quote GetQuoteForDayOfYear(int day); | 		Quote GetQuoteForDayOfYear(int day); | ||||||
|  | 		DefaultBrowseModel GetDefaultBrowseModel(); | ||||||
|  | 		void Delete(int id); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public class QuoteService : IQuoteService { | 	public class QuoteService : IQuoteService { | ||||||
| @ -53,6 +55,22 @@ namespace VideoGameQuotes.Web.Services { | |||||||
| 			this.publisherRepository = publisherRepository; | 			this.publisherRepository = publisherRepository; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		[UnitOfWork] | ||||||
|  | 		public DefaultBrowseModel GetDefaultBrowseModel() { | ||||||
|  | 			return new DefaultBrowseModel { | ||||||
|  | 				TotalNumberOfCategories = categoryRepository.Records.Count(), | ||||||
|  | 				TotalNumberOfSystems = systemRepository.Records.Count(), | ||||||
|  | 				TotalNumberOfPublishers = publisherRepository.Records.Count(), | ||||||
|  | 				TotalNumberOfGames = gameRepository.Records.Count(), | ||||||
|  | 				TotalNumberOfQuotes = quoteRepository.Records.Count() | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[UnitOfWork] | ||||||
|  | 		public void Delete(int id) { | ||||||
|  | 			quoteRepository.Delete(id); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		[UnitOfWork] | 		[UnitOfWork] | ||||||
| 		public Game GetGame(int id) { | 		public Game GetGame(int id) { | ||||||
| 			return gameRepository.FindById(id); | 			return gameRepository.FindById(id); | ||||||
|  | |||||||
| @ -105,6 +105,7 @@ | |||||||
|     </Reference> |     </Reference> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <Compile Include="Configuration\DeleteSearchIndexCallHandler.cs" /> | ||||||
|     <Compile Include="Configuration\EnableLogging.cs" /> |     <Compile Include="Configuration\EnableLogging.cs" /> | ||||||
|     <Compile Include="Configuration\EnableSearchWithLucene.cs" /> |     <Compile Include="Configuration\EnableSearchWithLucene.cs" /> | ||||||
|     <Compile Include="Configuration\UpdateSearchIndexCallHandler.cs" /> |     <Compile Include="Configuration\UpdateSearchIndexCallHandler.cs" /> | ||||||
| @ -115,6 +116,7 @@ | |||||||
|     <Compile Include="Controllers\HomeController.cs" /> |     <Compile Include="Controllers\HomeController.cs" /> | ||||||
|     <Compile Include="Controllers\PublisherController.cs" /> |     <Compile Include="Controllers\PublisherController.cs" /> | ||||||
|     <Compile Include="Controllers\SystemController.cs" /> |     <Compile Include="Controllers\SystemController.cs" /> | ||||||
|  |     <Compile Include="Models\DefaultBrowseModel.cs" /> | ||||||
|     <Compile Include="Models\EditCategoryModel.cs" /> |     <Compile Include="Models\EditCategoryModel.cs" /> | ||||||
|     <Compile Include="Models\EditGameModel.cs" /> |     <Compile Include="Models\EditGameModel.cs" /> | ||||||
|     <Compile Include="Models\EditPublisherModel.cs" /> |     <Compile Include="Models\EditPublisherModel.cs" /> | ||||||
| @ -210,6 +212,7 @@ | |||||||
|     <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\DeleteSuccess.aspx" /> | ||||||
|     <Content Include="Views\Shared\CaptchaJavaScript.ascx" /> |     <Content Include="Views\Shared\CaptchaJavaScript.ascx" /> | ||||||
|     <Content Include="Views\Shared\PagingMenu.ascx" /> |     <Content Include="Views\Shared\PagingMenu.ascx" /> | ||||||
|     <Content Include="Views\Quote\QuoteFormJavaScript.ascx" /> |     <Content Include="Views\Quote\QuoteFormJavaScript.ascx" /> | ||||||
| @ -236,7 +239,9 @@ | |||||||
|     <Content Include="Views\Shared\Unknown.aspx" /> |     <Content Include="Views\Shared\Unknown.aspx" /> | ||||||
|     <Content Include="Views\User\Edit.aspx" /> |     <Content Include="Views\User\Edit.aspx" /> | ||||||
|     <Content Include="Views\User\InvalidUsername.aspx" /> |     <Content Include="Views\User\InvalidUsername.aspx" /> | ||||||
|     <Content Include="Web.config" /> |     <Content Include="Web.config"> | ||||||
|  |       <SubType>Designer</SubType> | ||||||
|  |     </Content> | ||||||
|     <Content Include="Web.Debug.config"> |     <Content Include="Web.Debug.config"> | ||||||
|       <DependentUpon>Web.config</DependentUpon> |       <DependentUpon>Web.config</DependentUpon> | ||||||
|     </Content> |     </Content> | ||||||
|  | |||||||
| @ -1,14 +1,16 @@ | |||||||
| <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Views/Shared/Site.Master" %> | <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<VideoGameQuotes.Web.Models.DefaultBrowseModel>" MasterPageFile="~/Views/Shared/Site.Master" %> | ||||||
| <asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Browse</asp:Content> | <asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Browse</asp:Content> | ||||||
| <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> | <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> | ||||||
| 	<h2>Browse</h2> | 	<p> | ||||||
|  | 		There are currently <strong><%= Model.TotalNumberOfQuotes %></strong> quotes. Choose wisely. | ||||||
|  | 	</p> | ||||||
| 
 | 
 | ||||||
| 	<div id="browse-default-menu"> | 	<div id="browse-default-menu"> | ||||||
| 		<ul> | 		<ul> | ||||||
| 			<li><a href="#" id="browse-game">Games</a></li> | 			<li><a href="#" id="browse-game">Games</a> <small>(<%= Model.TotalNumberOfGames %>)</small></li> | ||||||
| 			<li><a href="#" id="browse-system">Systems</a></li> | 			<li><a href="#" id="browse-system">Systems</a> <small>(<%= Model.TotalNumberOfSystems %>)</small></li> | ||||||
| 			<li><a href="#" id="browse-category">Categories</a></li> | 			<li><a href="#" id="browse-category">Categories</a> <small>(<%= Model.TotalNumberOfCategories %>)</small></li> | ||||||
| 			<li><a href="#" id="browse-publisher">Publishers</a></li> | 			<li><a href="#" id="browse-publisher">Publishers</a> <small>(<%= Model.TotalNumberOfPublishers %>)</small></li> | ||||||
| 		</ul> | 		</ul> | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								Src/VideoGameQuotes.Web/Views/Quote/DeleteSuccess.aspx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Src/VideoGameQuotes.Web/Views/Quote/DeleteSuccess.aspx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Views/Shared/Site.Master" %> | ||||||
|  | <asp:Content runat="server" ID="Title" ContentPlaceHolderID="TitleContent">Quote Successfully Deleted</asp:Content> | ||||||
|  | <asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent"> | ||||||
|  | 	<h2>Wild Success!</h2> | ||||||
|  | 
 | ||||||
|  | 	<p> | ||||||
|  | 		The quote and all its votes and flags were deleted. | ||||||
|  | 	</p> | ||||||
|  | </asp:Content> | ||||||
| @ -16,8 +16,8 @@ | |||||||
| 			</p> | 			</p> | ||||||
| 
 | 
 | ||||||
| 			<p> | 			<p> | ||||||
| 				Anyway, try <%= Html.ActionLink("searching", "Search", "Quote") %> for the quote | 				Anyway, try searching for the quote	you were hoping to find using the little search box up | ||||||
| 				you were hoping to find. Maybe that will make you less of a stain on humanity. | 				there in the top right corner. Maybe that will make you less of a stain on humanity. | ||||||
| 			</p> | 			</p> | ||||||
| 
 | 
 | ||||||
| 			<p> | 			<p> | ||||||
|  | |||||||
| @ -28,11 +28,12 @@ | |||||||
| 			</p> | 			</p> | ||||||
| 
 | 
 | ||||||
| 			<p class="quote-links"> | 			<p class="quote-links"> | ||||||
| 				<a class="quote-flag-icon" href="#" title="flag this quote as inaccurate, fake, spam, duplicate, etc."></a> | 				<a class="quote-flag-icon quote-flag-link" href="#" title="flag this quote as inaccurate, fake, spam, duplicate, etc."></a> | ||||||
| 				<a class="quote-permalink" href="<%= Url.Action("Quote", "Quote", new { id = Model.Quote.Id, text = Model.Quote.GetUrlFriendlyText() }) %>" title="permanent link to this quote"></a> | 				<a class="quote-permalink" href="<%= Url.Action("Quote", "Quote", new { id = Model.Quote.Id, text = Model.Quote.GetUrlFriendlyText() }) %>" title="permanent link to this quote"></a> | ||||||
| 				<% if (Model.User != null && Model.User.Group >= UserGroup.Admin) { %> | 				<% if (Model.User != null && Model.User.Group >= UserGroup.Admin) { %> | ||||||
| 				<a class="edit-icon" href="<%= Url.Action("Edit", "Quote", new { id = Model.Quote.Id }) %>" title="edit this quote"></a> | 				<a class="edit-icon" href="<%= Url.Action("Edit", "Quote", new { id = Model.Quote.Id }) %>" title="edit this quote"></a> | ||||||
| 				<small>(<%= Model.Quote.FlagCount %>)</small> | 				<a class="delete-icon delete-quote-link" href="#" title="delete this quote and all its flags and votes"></a> | ||||||
|  | 				<strong>[<%= Model.Quote.FlagCount %>]</strong> | ||||||
| 				<% } %> | 				<% } %> | ||||||
| 			</p> | 			</p> | ||||||
| 		</div> | 		</div> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user