using System; 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.Controllers; using Portoa.Web.Results; using VideoGameQuotes.Api; using VideoGameQuotes.Api.Search; 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; private readonly IQuoteSearcher quoteSearcher; public QuoteController(IQuoteService quoteService, ICurrentUserProvider currentUserProvider, IQuoteSearcher quoteSearcher) { this.quoteService = quoteService; this.currentUserProvider = currentUserProvider; this.quoteSearcher = quoteSearcher; } public ActionResult Browse(BrowseModel model) { if (model.IsEmpty) { return View("DefaultBrowse"); } return View("QualifiedBrowse", new QualifiedBrowseModel(model) { Quotes = quoteService.GetBrowsableQuotes(model), User = currentUserProvider.CurrentUser }); } [HttpPost, IsValidUser] public JsonResult Report(ReportModel model) { if (!ModelState.IsValid) { return Json(this.CreateJsonErrorResponse("Invalid request")); } try { var quote = quoteService.GetQuote(model.QuoteId); quote.AddFlag(model.Comment, model.FlagType, currentUserProvider.CurrentUser); quoteService.SaveQuote(quote); return Json(this.CreateJsonResponse()); } catch (Exception e) { return Json(this.CreateJsonErrorResponse("Unable to create your report")); } } [HttpPost, IsValidUser] public JsonResult Vote(VoteModel model) { if (!ModelState.IsValid) { return Json(this.CreateJsonErrorResponse("Invalid request")); } try { var vote = quoteService.GetVoteOrCreateNew(quoteService.GetQuote(model.QuoteId), currentUserProvider.CurrentUser); vote.Direction = model.Direction; vote = quoteService.SaveVote(vote); var data = new Dictionary { { "netVotes", vote.Quote.Score.ToString() }, { "upVotes", vote.Quote.UpVotes.ToString() }, { "downVotes", vote.Quote.DownVotes.ToString() } }; return Json(this.CreateJsonResponse(null, data)); } catch { return Json(this.CreateJsonErrorResponse("An error occurred while trying to process your vote")); } } public ActionResult Recent() { return View(new QuoteCollectionModel { Quotes = quoteService.GetMostRecentQuotes(10), User = currentUserProvider.CurrentUser }); } public ActionResult Best(int start = 0, int end = 19) { if (start < 0 || end <= 0 || start > end) { return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; } return View(new PagedQuoteCollectionModel { Quotes = quoteService.GetBestQuotes(start, end), User = currentUserProvider.CurrentUser, Start = start, End = end }); } public ActionResult Random() { var quote = quoteService.GetRandomQuote(); if (quote == null) { return View("NoQuotes"); } return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() }); } [HttpPost, IsValidUser(Group = UserGroup.Admin)] public ActionResult DismissFlag([GreaterThanZero]int quoteId, [GreaterThanZero]int flagId) { if (!ModelState.IsValid) { return Json(this.CreateJsonErrorResponse("quote/flag is invalid")); } try { var quote = quoteService.GetQuote(quoteId); var flag = quote.Flags.FirstOrDefault(f => f.Id == flagId); if (flag == null) { return Json(this.CreateJsonErrorResponse(string.Format("Flag {0} not found for quote {1}", flagId, quote.Id))); } quote.RemoveFlag(flag); quoteService.SaveQuote(quote); return Json(this.CreateJsonResponse()); } catch (Exception e) { return Json(this.CreateJsonErrorResponse(e)); } } [HttpGet, IsValidUser(Group = UserGroup.Admin)] public ActionResult Edit(int id) { try { var model = new EditQuoteModel(quoteService.GetQuote(id)); ResetEditQuoteModel(model); return View(model); } catch (EntityNotFoundException) { return View("QuoteNotFound"); } } [HttpPost, IsValidUser(Group = UserGroup.Admin)] public ActionResult Edit(EditQuoteModel model) { return CreateOrEditQuote(model, "Edit"); } [IsValidUser] public ActionResult Submit() { var model = new EditQuoteModel(); ResetEditQuoteModel(model); return View(model); } [HttpPost, IsValidUser] public ActionResult Submit(EditQuoteModel model) { return CreateOrEditQuote(model, "Submit"); } private ActionResult CreateOrEditQuote(EditQuoteModel model, string viewName) { if (!ModelState.IsValid) { ResetEditQuoteModel(model); return View(viewName, model); } try { var quote = model.QuoteId > 0 ? quoteService.GetQuote(model.QuoteId) : new Quote {Creator = currentUserProvider.CurrentUser}; quote.Game = GetGameFromModelData(model); quote.Text = model.QuoteText; if (model.CategoryIds != null && model.CategoryIds.Count > 0) { quote.ClearCategories(); foreach (var categoryId in model.CategoryIds) { quote.AddCategory(quoteService.GetCategory(categoryId)); } } if (quote.Game == null) { ResetEditQuoteModel(model); return View(viewName, model); } quote = quoteService.SaveQuote(quote); return RedirectToAction("Quote", new {id = quote.Id, text = quote.GetUrlFriendlyText()}); } catch (Exception e) { ModelState.AddModelError("save", e.Message); ResetEditQuoteModel(model); return View(viewName, model); } } [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); model.AllPublishers = quoteService.GetAllPublishers().OrderBy(publisher => publisher.Name); model.AllCategories = quoteService.GetAllCategories().OrderBy(category => category.Name); } public ActionResult Quote(int id) { try { var model = new QuoteModel { Quote = quoteService.GetQuote(id), User = currentUserProvider.CurrentUser }; return View(model); } catch (EntityNotFoundException) { return new StatusOverrideResult(View("QuoteNotFound")) { StatusCode = HttpStatusCode.NotFound }; } } [IsValidUser(Group = UserGroup.Admin)] public ActionResult Flags(int id) { try { var model = new QuoteModel { Quote = quoteService.GetQuote(id), User = currentUserProvider.CurrentUser }; return View(model); } catch (EntityNotFoundException) { return new StatusOverrideResult(View("QuoteNotFound")) { StatusCode = HttpStatusCode.NotFound }; } } [HttpPost, IsValidUser] public JsonResult CreateCategory(Category category) { try { category = quoteService.SaveCategory(category); var data = new Dictionary { { "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, Results = quoteSearcher.Search(searchQuery), SearchQuery = searchQuery }; return View(model); } } }