using System; using System.Linq; using System.Net; using System.Web.Mvc; using Portoa.Persistence; using Portoa.Search; using Portoa.Validation.DataAnnotations; using Portoa.Web.Controllers; using Portoa.Web.Filters; using Portoa.Web.Models; using Portoa.Web.Results; using Portoa.Web.Security; 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; private readonly ISearcher quoteSearcher; public QuoteController(IQuoteService quoteService, ICurrentUserProvider currentUserProvider, ISearcher quoteSearcher) { this.quoteService = quoteService; this.currentUserProvider = currentUserProvider; this.quoteSearcher = quoteSearcher; } protected new ActionResult Json(object 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) { if (page < 1) { return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; } if (model.IsEmpty) { return View("DefaultBrowse", quoteService.GetDefaultBrowseModel()); } model.CurrentUser = currentUserProvider.CurrentUser; var pagingModel = new PagedModel { CurrentPage = page, PageSize = 10 }; int totalCount; var quotes = quoteService.GetBrowsableQuotes(model, pagingModel.Start, pagingModel.End, out totalCount); pagingModel.Records = quotes; pagingModel.TotalCount = totalCount; return View("QualifiedBrowse", new QualifiedBrowseModel(model) { PagedModel = pagingModel }); } [HttpPost, VerifyUser] public ActionResult Flag(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 { return Json(this.CreateJsonErrorResponse("Unable to create your report")); } } [HttpPost, VerifyUser] public ActionResult Vote(VoteModel model) { if (!ModelState.IsValid) { return Json(this.CreateJsonErrorResponse("Invalid request")); } try { var quote = quoteService.SaveQuote(quoteService.GetQuote(model.QuoteId).VoteFor(currentUserProvider.CurrentUser, model.Direction)); var data = new { score = quote.Score, upVotes = quote.UpVotes, downVotes = quote.DownVotes }; return Json(this.CreateJsonResponse(null, data)); } catch (CannotVoteTwiceException) { return Json(this.CreateJsonErrorResponse("You have already voted for this quote; you can reverse your vote by voting in the other direction")); } catch { return Json(this.CreateJsonErrorResponse("An error occurred while trying to process your vote")); } } public ActionResult Recent(int page) { if (page < 1) { return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; } const int pageSize = 10; int totalCount; var model = new PagedModelWithUser { CurrentUser = currentUserProvider.CurrentUser, CurrentPage = page, PageSize = pageSize }; model.Records = quoteService.GetRecentQuotes(model.Start, model.End, out totalCount); model.TotalCount = totalCount; return View(model); } public ActionResult Best(int page) { if (page < 1) { return new StatusOverrideResult(View("BadPaging")) { StatusCode = HttpStatusCode.BadRequest }; } const int pageSize = 10; int totalCount; var model = new PagedModelWithUser { CurrentUser = currentUserProvider.CurrentUser, CurrentPage = page, PageSize = pageSize }; model.Records = quoteService.GetBestQuotes(model.Start, model.End, out totalCount); model.TotalCount = totalCount; return View(model); } public ActionResult Random() { var quote = quoteService.GetRandomQuote(); if (quote == null) { return View("NoQuotes"); } return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() }); } [PrivateAction] public ActionResult QuoteOfTheDay() { var today = DateTime.UtcNow.DayOfYear; var quote = quoteService.GetQuoteForDayOfYear(today); return PartialView("QuoteOfTheDay", quote); } [HttpPost, VerifyUser(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, VerifyUser(Group = UserGroup.Admin)] public ActionResult Edit(int id) { if (id < 1) { return View("QuoteNotFound"); } try { return View(ResetEditQuoteModel(new EditQuoteModel(quoteService.GetQuote(id)))); } catch (EntityNotFoundException) { return View("QuoteNotFound"); } } [HttpPost, VerifyUser(Group = UserGroup.Admin)] public ActionResult Edit(EditQuoteModelBase model) { return CreateOrEditQuote(model, "Edit"); } [VerifyUser] public ActionResult Submit() { return View(ResetEditQuoteModel(new SubmitQuoteModel())); } [HttpPost, VerifyUser] public ActionResult Submit(SubmitQuoteModel model) { if (CaptchaUtil.Hash(model.CaptchaAnswer) != model.HashedCaptchaAnswer) { ModelState.AddModelError("CaptchaAnswer", "You are not human"); } return CreateOrEditQuote(model, "Submit"); } private ActionResult CreateOrEditQuote(EditQuoteModelBase model, string viewName) { if (!ModelState.IsValid) { model = ResetEditQuoteModel(model); return View(viewName, model); } try { var editModel = model as EditQuoteModel; var quote = editModel != null && editModel.QuoteId > 0 ? quoteService.GetQuote(editModel.QuoteId) : new Quote { Creator = currentUserProvider.CurrentUser }; quote.Game = new Game { Id = model.GameId }; quote.Text = model.QuoteText; if (model.CategoryIds != null && model.CategoryIds.Count > 0) { quote.ClearCategories(); foreach (var categoryId in model.CategoryIds) { quote.AddCategory(new Category { Id = categoryId }); } } if (quote.Game == null) { return View(viewName, ResetEditQuoteModel(model)); } quote = quoteService.SaveQuote(quote); return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() }); } catch (Exception e) { ModelState.AddModelError("save", e.Message); return View(viewName, ResetEditQuoteModel(model)); } } private EditQuoteModelBase ResetEditQuoteModel(EditQuoteModelBase model) { model.CurrentUser = currentUserProvider.CurrentUser; 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); var submitModel = model as SubmitQuoteModel; if (submitModel != null) { submitModel.UnhashedCaptchaAnswer = CaptchaUtil.GetRandomAnswer(); submitModel.HashedCaptchaAnswer = CaptchaUtil.Hash(submitModel.UnhashedCaptchaAnswer); submitModel.CaptchaAnswer = null; return submitModel; } return model; } public ActionResult Quote(int id, string text = null) { 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 }; } } [VerifyUser(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 }; } } public ActionResult Search(string searchQuery) { var model = new SearchModel { User = currentUserProvider.CurrentUser, Results = quoteSearcher.Search(searchQuery), SearchQuery = searchQuery }; return View(model); } } }