quote of the day, added external image

This commit is contained in:
tmont 2011-02-28 00:38:47 +00:00
parent 86b0918ca5
commit 602a722277
13 changed files with 164 additions and 70 deletions

View File

@ -135,6 +135,13 @@ namespace VideoGameQuotes.Web.Controllers {
return RedirectToAction("Quote", new { id = quote.Id, text = quote.GetUrlFriendlyText() });
}
[ChildActionOnly]
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) {

View File

@ -63,6 +63,7 @@ namespace VideoGameQuotes.Web {
//bullshit route so that RenderAction works
routes.MapRoute("mainmenu", "home/mainmenu", new { controller = "Home", action = "MainMenu" });
routes.MapRoute("quote-of-the-day", "quote/quoteoftheday", new { controller = "Quote", action = "QuoteOfTheDay" });
routes.MapRoute("crud-default", "{controller}/{action}", null, new { controller = "system|publisher|game|category", action = "create|edit|delete" });

View File

@ -24,6 +24,7 @@ namespace VideoGameQuotes.Web.Services {
IEnumerable<Quote> GetBestQuotes(int start, int end, out int totalCount);
Vote GetVoteOrCreateNew(Quote quote, User voter);
IEnumerable<Quote> GetBrowsableQuotes(BrowseModel model, int start, int end, out int totalCount);
Quote GetQuoteForDayOfYear(int day);
}
public class QuoteService : IQuoteService {
@ -34,6 +35,7 @@ namespace VideoGameQuotes.Web.Services {
private readonly IRepository<Category> categoryRepository;
private readonly IRepository<Vote> voteRepository;
private static readonly Random random = new Random();
private static readonly IDictionary<int, Quote> quoteOfTheDayMap = new Dictionary<int, Quote>();
public QuoteService(
IRepository<Quote> quoteRepository,
@ -118,8 +120,16 @@ namespace VideoGameQuotes.Web.Services {
return null;
}
return quoteRepository
.Records
return GetRandomQuote(quoteRepository.Records);
}
private static Quote GetRandomQuote(IEnumerable<Quote> quotes) {
var length = quotes.Count();
if (length == 0) {
return null;
}
return quotes
.Skip(random.Next(length))
.Take(1)
.Single();
@ -164,5 +174,15 @@ namespace VideoGameQuotes.Web.Services {
totalCount = quotes.Count();
return quotes.Skip(start - 1).Take(end - start + 1);
}
[UnitOfWork, CanBeNull]
public Quote GetQuoteForDayOfYear(int day) {
if (!quoteOfTheDayMap.ContainsKey(day)) {
quoteOfTheDayMap[day] = GetRandomQuote(quoteRepository.Records.Where(quote => quote.Score > 0));
}
return quoteOfTheDayMap[day];
}
}
}

View File

@ -149,6 +149,7 @@
<Content Include="media\images\cancel.png" />
<Content Include="media\images\delete.png" />
<Content Include="media\images\error.png" />
<Content Include="media\images\external.png" />
<Content Include="media\images\favicon.png" />
<Content Include="media\images\flag_red.png" />
<Content Include="media\images\link.png" />
@ -172,6 +173,7 @@
<Content Include="Views\Home\Contact.aspx" />
<Content Include="Views\Home\ContactSuccess.aspx" />
<Content Include="Views\Quote\PagingMenu.ascx" />
<Content Include="Views\Quote\QuoteOfTheDay.ascx" />
<Content Include="Views\Shared\BadPaging.aspx" />
<Content Include="Views\Quote\Best.aspx" />
<Content Include="Views\Quote\Edit.aspx" />

View File

@ -3,45 +3,45 @@
<asp:Content runat="server" ID="Main" ContentPlaceHolderID="MainContent">
<h2>About</h2>
<div class="inset">
<h3>Genesis</h3>
<div class="inset">
<p>
<strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave
myself a week to implement everything and throw it up on the internet.
</p>
<p>
<strong>Video Game Quotes</strong> is a little project that I decided to tackle one day. I gave
myself a week to implement everything and throw it up on the internet. It actually took three
weeks as I struggled with <a href="http://incubator.apache.org/lucene.net/" class="external">Lucene</a> and my
obviously poor graphic design skills.
</p>
<p>
The inspiration for the site was that there were a lot of awesome video game quotes, but sadly,
no central place to go to find/search/read them. That made me sad.
</p>
<p>
The inspiration for the site was that there were a lot of awesome video game quotes, but sadly,
no central place to go to find/search/read them. That made me sad.
</p>
<p>
The infrastructure is modeled after <a href="http://bash.org/">bash.org</a>, which is a database
of IRC quotes. One thing I wanted to make sure of was that it shouldn't require you to login or
register. No email addresses, or usernames, or passwords. The site keeps track of who has voted
for what based on IP address, which admittedly is a quite fragile. But it's the only way to
unique-ish-ly identify someone without requiring a login. So, you could totally game the system
by voting, resetting your router, closing your browser, and voting again. I won&#39;t stop you.
</p>
</div>
<p>
The infrastructure is modeled after <a href="http://bash.org/" class="external">bash.org</a>, which is a database
of IRC quotes. One thing I wanted to make sure of was that it shouldn&rsquo;t require you to login or
register. No email addresses, or usernames, or passwords. The site keeps track of who has voted
for what based on IP address, which admittedly is a quite fragile. But it&rsquo;s the only way to
unique-ish-ly identify someone without requiring a login. So, you could totally game the system
by voting, resetting your router, closing your browser, and voting again. I won&rsquo;t stop you.
</p>
<h3>Technical Details</h3>
<div class="inset">
<p>
The site was written in C&#9839; using <a href="http://www.asp.net/mvc">ASP.NET MVC 2</a>,
<a href="http://unity.codeplex.com/">Unity</a> and <a href="http://nhforge.org/">NHibernate</a>.
It runs on <a href="http://nginx.org/">nginx</a> using <a href="http://www.mono-project.com/">Mono</a>
via FastCGI on Ubuntu. It uses MySQL for the backend.
</p>
</div>
<p>
The site was written in C&#9839; using <a href="http://www.asp.net/mvc" class="external">ASP.NET MVC 2</a>,
<a href="http://unity.codeplex.com/" class="external">Unity</a> and <a href="http://nhforge.org/" class="external">NHibernate</a>.
It runs on <a href="http://nginx.org/" class="external">nginx</a> using <a href="http://www.mono-project.com/" class="external">Mono</a>
via FastCGI on Ubuntu. It uses MySQL for the backend and
<a href="http://incubator.apache.org/lucene.net/" class="external">Lucene.NET</a> for search indexing.
</p>
<h3>Get in Touch</h3>
<div class="inset">
<p>
If you have any questions, concerns, comments, insults or death threats, don&#39;t hesitate to
<%= Html.ActionLink("contact me", "Contact", "Home") %>.
</p>
</div>
</div>
<p>
If you have any questions, concerns, comments, insults or death threats, don&rsquo;t hesitate to
<%= Html.ActionLink("contact me", "Contact", "Home") %> and you will be ignored immediately.
</p>
<h3><a name="credits"></a>Credits</h3>
<p>
Some of the icons and images used on this site were taken from the
<a href="http://www.famfamfam.com/lab/icons/silk/" class="external">silk icon set</a> and
<a href="http://deleket.deviantart.com/art/Gaming-Icons-Pack-42723812" class="external">deleket&rsquo;s
gaming icon set</a>.
</p>
</asp:Content>

View File

@ -27,4 +27,6 @@
<p>
Here is the quote of the day:
</p>
<% Html.RenderAction("QuoteOfTheDay", "Quote"); %>
</asp:Content>

View File

@ -0,0 +1,20 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<VideoGameQuotes.Api.Quote>" %>
<%@ Import Namespace="VideoGameQuotes.Api" %>
<div class="quote-container">
<div class="quote-data clearfix">
<div class="quote-score-container">
<div class="vote-container">
</div>
<div class="quote-score" title="+<%= Model.UpVotes %>, -<%= Model.DownVotes %>"><%= Model.Score %></div>
<div class="vote-container">
</div>
</div>
<div class="quote-text">
<a href="<%= Url.Action("quote", "quote", new { id = Model.Id, text = Model.GetUrlFriendlyText() }) %>">
<%= Model.FormatTextForHtml() %>
</a>
</div>
</div>
</div>

View File

@ -37,7 +37,8 @@
<div id="footer">
<p>
&copy; <%= DateTime.UtcNow.Year %> <a href="http://tommymontgomery.com/" title="Who is this man?">Tommy Montgomery</a><br />
<%= Html.ActionLink("about", "about", "home") %> |
<%= Html.ActionLink("about", "about", "home") %> |
<%= Html.ActionLink("credits", "about", "home", null, null, "credits", null, null) %> |
<% if (!Request.IsAuthenticated) { %>
<a href="#" id="login-link">login</a>
<% } else { %>

View File

@ -50,6 +50,12 @@ ul.menu {
padding: 0;
list-style: none;
}
a.external {
background-image: url(/media/images/external.png);
background-position: right center;
background-repeat: no-repeat;
padding-right: 14px;
}
.error-message {
padding-left: 18px;
@ -252,7 +258,7 @@ ul.menu {
}
#main {
padding: 20px 20px 100px 20px;
padding: 20px 20px 120px 20px;
}
#main a {
color: #669966;
@ -306,6 +312,9 @@ ul.menu {
color: inherit;
text-decoration: none;
}
#footer p {
margin-top: 30px;
}
#footer a:hover {
text-decoration: underline;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

After

Width:  |  Height:  |  Size: 615 B

View File

@ -48,7 +48,12 @@
var $container = $("#create-system-form");
var $link = $(this);
var data = { SystemName: $("#SystemName").val(), SystemAbbreviation: $("#SystemAbbreviation").val(), SystemReleaseDate: $("#SystemReleaseDate").val() };
var data = {
SystemName: $("#SystemName").val(),
SystemAbbreviation: $("#SystemAbbreviation").val(),
SystemReleaseDate: $("#SystemReleaseDate").val(),
SystemIcon: $("#SystemIcon").val()
};
var url = "/system/create";
var systemId = $container.find("> .edit-mode").val();
@ -111,6 +116,7 @@
$("#SystemName").val(system.Name);
$("#SystemAbbreviation").val(system.Abbreviation);
$("#SystemReleaseDate").val($.vgquotes.parseAndFormatDate(system.ReleaseDate));
$("#SystemIcon").val(system.Icon);
});
return false;
@ -218,6 +224,7 @@
//populate game form with game data
$("#GameName").val(game.Name);
$("#GameWebsite").val(game.Website);
$("#GameIcon").val(game.Icon);
$.each(game.Regions, function() {
$("input[name='GameRegions'][value='" + this + "']").attr("checked", "checked");
});

View File

@ -1,11 +1,12 @@
(function($, window, undefined){
$.fn.center = function() {
this.css("top", ($(window).height() - this.height()) / 2 + $(window).scrollTop() + "px");
this.css("left", ($(window).width() - this.width()) / 2 + $(window).scrollLeft() + "px");
var fixed = this.css("position") === "fixed";
this.css("top", ($(window).height() - this.height()) / 2 + (fixed ? 0 : $(window).scrollTop()) + "px");
this.css("left", ($(window).width() - this.width()) / 2 + (fixed ? 0 : $(window).scrollLeft()) + "px");
return this;
};
$.fn.applyModelErrors = function(errorMessage, errorData) {
var $this = this;
@ -70,7 +71,6 @@
alert("An error occurred (" + xhr.status + ")");
},
preload: function(images) {
//MM_preloadImages(lulz)
$.each(images, function() {
$('<img/>')[0].src = this;
});
@ -83,6 +83,17 @@
success: ajaxCallback(type, callback),
error: ajaxCallback(type, callback)
});
},
createDialog: function($dialog) {
$("body")
.append($("<div/>").attr("id", "modal-background"))
.append($dialog);
$dialog.center();
},
closeDialog: function($dialog) {
$("#modal-background").remove();
$dialog.remove();
}
};
}();
@ -203,11 +214,12 @@
});
};
var setupReportLink = function() {
$(".quote-flag-link").click(function() {
if ($(".report-dialog").length > 0) {
var setupFlagLink = function() {
$("a.quote-flag-link").click(function() {
if ($(".flag-dialog").length > 0) {
return false;
}
var $link = $(this);
var $container = $link.parents(".quote-container");
var quoteId = $container.find("input.quote-id").val();
@ -222,42 +234,51 @@
$row.append($(html));
}
var $dialog = $("<div/>").addClass("dialog report-dialog");
var $dialog = $("<div/>").addClass("dialog flag-dialog");
var $submit = $("<input/>")
.attr("type", "button")
.attr("value", "Submit Report")
var $submit = $("<a/>")
.attr({ href: "#", title: "submit" })
.addClass("submit-link button-link")
.text("Submit")
.click(function() {
$.ajax("/report", {
var $link = $(this);
$link.toggleClass("submit-link loading-link");
$.ajax("/flag", {
type: "POST",
data: { QuoteId: quoteId, Comment: $dialog.find("textarea").val(), FlagType: $dialog.find("input[name='flagType']:checked").val() },
complete: function() { $dialog.remove(); },
success: function(data, status, $xhr) {
if (data.Error !== null) {
alert(data.Error);
return;
}
}
$.vgquotes.closeDialog($dialog);
},
complete: function() { $link.toggleClass("submit-link loading-link"); }
});
return false;
});
var $cancel = $("<input/>")
.attr("type", "button")
.attr("value", "Cancel")
.click(function() { $dialog.remove(); });
var $cancel = $("<a/>")
.attr({ href: "#", title: "cancel" })
.addClass("cancel-link button-link")
.text("Cancel")
.click(function() { $.vgquotes.closeDialog($dialog); return false; });
$dialog
.append($("<p/>").text("Flag as:"))
.append($("<p/>").addClass("label").text("Flag as:"))
.append($("<table/>").append($row))
.append($("<p/>").text("Comment"))
.append($("<p/>").addClass("label").text("Comment"))
.append($("<textarea/>"))
.append($("<div/>").css("text-align", "center").append($submit).append($cancel));
.append($("<div/>").addClass("submit-container").append($submit).append($cancel));
//"other" should be checked by default
$dialog.find("#flag-type-0").attr("checked", "checked");
$("body").append($dialog);
$dialog.center();
$.vgquotes.createDialog($dialog);
return false;
});
@ -267,7 +288,7 @@
var showLoginForm = function() {
var $dialog = $("#login-dialog");
if ($dialog.length > 0) {
$dialog.remove();
$.vgquotes.closeDialog($dialog);
return false;
}
@ -292,13 +313,12 @@
return false;
});
var $dialog = $("<div/>").addClass("dialog").attr("id", "login-dialog");
$dialog = $("<div/>").addClass("dialog").attr("id", "login-dialog");
$form.append($usernameInput).append($passwordInput).append($submit);
$dialog.append($form);
$("body").append($dialog);
$dialog.center();
$.vgquotes.createDialog($dialog);
$usernameInput.focus();
return false;
@ -315,7 +335,7 @@
$(document).ready(function() {
$.vgquotes.preload([$.vgquotes.loadingGif]);
setupReportLink();
setupFlagLink();
setupVoting();
$("body").ajaxError(function(e, xhr, options, error){
@ -323,6 +343,11 @@
});
$("#search-query").focus();
$(document).keyup(function(e) {
if (e.keyCode === 27) {
$.vgquotes.closeDialog($(".dialog"));
}
});
});
}());