2011-02-09 00:05:32 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2011-02-14 07:39:45 +00:00
|
|
|
|
using System.Text.RegularExpressions;
|
2011-02-27 04:20:59 +00:00
|
|
|
|
using System.Web;
|
2011-02-09 00:05:32 +00:00
|
|
|
|
using Iesi.Collections.Generic;
|
|
|
|
|
using Portoa.Persistence;
|
2011-02-26 01:22:07 +00:00
|
|
|
|
using Portoa.Search;
|
2011-02-09 00:05:32 +00:00
|
|
|
|
|
|
|
|
|
namespace VideoGameQuotes.Api {
|
2011-02-26 01:22:07 +00:00
|
|
|
|
public class Quote : Entity<Quote, int>, IDtoMappable<QuoteDto>, ISearchable {
|
|
|
|
|
private string text;
|
2011-02-09 00:05:32 +00:00
|
|
|
|
private readonly Iesi.Collections.Generic.ISet<Vote> votes = new HashedSet<Vote>();
|
|
|
|
|
private readonly Iesi.Collections.Generic.ISet<QuoteFlag> flags = new HashedSet<QuoteFlag>();
|
2011-02-12 23:53:43 +00:00
|
|
|
|
private readonly Iesi.Collections.Generic.ISet<Category> categories = new HashedSet<Category>();
|
2011-02-09 00:05:32 +00:00
|
|
|
|
|
2011-02-09 03:41:35 +00:00
|
|
|
|
public Quote() {
|
|
|
|
|
Created = DateTime.UtcNow;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 00:05:32 +00:00
|
|
|
|
public virtual User Creator { get; set; }
|
|
|
|
|
public virtual DateTime Created { get; set; }
|
|
|
|
|
public virtual DateTime? Modified { get; set; }
|
|
|
|
|
|
2011-02-26 01:22:07 +00:00
|
|
|
|
public virtual string Text {
|
|
|
|
|
get { return text; }
|
|
|
|
|
set {
|
|
|
|
|
if (value != text) {
|
|
|
|
|
ShouldIndex = true;
|
|
|
|
|
}
|
2011-02-09 00:05:32 +00:00
|
|
|
|
|
2011-02-26 01:22:07 +00:00
|
|
|
|
text = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual Game Game { get; set; }
|
2011-02-09 00:05:32 +00:00
|
|
|
|
public virtual IEnumerable<Vote> Votes { get { return votes; } }
|
|
|
|
|
public virtual IEnumerable<QuoteFlag> Flags { get { return flags; } }
|
2011-02-12 23:53:43 +00:00
|
|
|
|
public virtual IEnumerable<Category> Categories { get { return categories; } }
|
2011-02-09 00:05:32 +00:00
|
|
|
|
|
2011-02-12 23:53:43 +00:00
|
|
|
|
#region adding and removing stuff
|
|
|
|
|
public virtual Quote AddCategory(Category category) {
|
|
|
|
|
categories.Add(category);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCategories() {
|
|
|
|
|
categories.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-15 01:18:23 +00:00
|
|
|
|
public virtual Quote AddFlag(string comment, QuoteFlagType type, User user) {
|
2011-02-27 01:41:07 +00:00
|
|
|
|
var flag = new QuoteFlag {
|
2011-02-15 01:18:23 +00:00
|
|
|
|
Comment = comment,
|
|
|
|
|
Type = type,
|
|
|
|
|
User = user,
|
|
|
|
|
Quote = this
|
2011-02-27 01:41:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (flags.Add(flag)) {
|
|
|
|
|
FlagCount++;
|
|
|
|
|
}
|
2011-02-15 01:18:23 +00:00
|
|
|
|
|
2011-02-12 23:53:43 +00:00
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-19 09:41:09 +00:00
|
|
|
|
public virtual Quote RemoveFlag(QuoteFlag flag) {
|
2011-02-27 01:41:07 +00:00
|
|
|
|
if (flags.Remove(flag)) {
|
|
|
|
|
FlagCount--;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-19 09:41:09 +00:00
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-12 23:53:43 +00:00
|
|
|
|
public virtual void ClearFlags() {
|
|
|
|
|
flags.Clear();
|
2011-02-27 01:41:07 +00:00
|
|
|
|
FlagCount = 0;
|
2011-02-12 23:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
public virtual Quote VoteFor(User user, VoteDirection direction) {
|
2011-02-09 00:05:32 +00:00
|
|
|
|
var currentVote = votes.SingleOrDefault(vote => vote.Voter == user);
|
|
|
|
|
if (currentVote != null) {
|
2011-02-10 20:34:55 +00:00
|
|
|
|
if (currentVote.Direction == direction) {
|
|
|
|
|
throw new CannotVoteTwiceException();
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 00:05:32 +00:00
|
|
|
|
votes.Remove(currentVote);
|
2011-02-23 09:19:32 +00:00
|
|
|
|
if (currentVote.Direction == VoteDirection.Up) {
|
|
|
|
|
UpVotes--;
|
|
|
|
|
} else {
|
|
|
|
|
DownVotes--;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-10 20:34:55 +00:00
|
|
|
|
currentVote.Direction = direction;
|
|
|
|
|
currentVote.Created = DateTime.UtcNow;
|
2011-02-09 00:05:32 +00:00
|
|
|
|
votes.Add(currentVote);
|
|
|
|
|
} else {
|
2011-02-10 20:34:55 +00:00
|
|
|
|
votes.Add(new Vote { Direction = direction, Quote = this, Voter = user });
|
2011-02-09 00:05:32 +00:00
|
|
|
|
}
|
2011-02-12 23:53:43 +00:00
|
|
|
|
|
2011-02-23 09:19:32 +00:00
|
|
|
|
if (direction == VoteDirection.Up) {
|
|
|
|
|
UpVotes++;
|
|
|
|
|
} else {
|
|
|
|
|
DownVotes++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Score = UpVotes - DownVotes;
|
|
|
|
|
|
2011-02-12 23:53:43 +00:00
|
|
|
|
return this;
|
2011-02-09 00:05:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 11:01:31 +00:00
|
|
|
|
public virtual VoteDirection? VotedFor(User user) {
|
|
|
|
|
var vote = Votes.Where(v => v.Voter == user).SingleOrDefault();
|
|
|
|
|
if (vote == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vote.Direction;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-23 09:19:32 +00:00
|
|
|
|
public virtual int UpVotes { get; private set; }
|
|
|
|
|
public virtual int DownVotes { get; private set; }
|
|
|
|
|
public virtual int Score { get; private set; }
|
2011-02-27 01:41:07 +00:00
|
|
|
|
public virtual int FlagCount { get; private set; }
|
2011-02-16 10:11:55 +00:00
|
|
|
|
|
2011-02-16 02:48:11 +00:00
|
|
|
|
public virtual QuoteDto ToDto() {
|
|
|
|
|
return new QuoteDto {
|
|
|
|
|
Id = Id,
|
|
|
|
|
Text = Text,
|
|
|
|
|
Game = Game.ToDto(),
|
|
|
|
|
Created = Created,
|
|
|
|
|
Categories = Categories.Select(category => category.ToDto()),
|
2011-02-28 01:03:49 +00:00
|
|
|
|
TotalVotes = UpVotes + DownVotes,
|
2011-02-16 02:48:11 +00:00
|
|
|
|
UpVotes = UpVotes,
|
|
|
|
|
DownVotes = DownVotes,
|
|
|
|
|
Score = Score
|
|
|
|
|
};
|
|
|
|
|
}
|
2011-02-16 10:11:55 +00:00
|
|
|
|
|
|
|
|
|
#region nested types
|
|
|
|
|
public class GameCriterionHandler : CriterionHandler<Quote> {
|
|
|
|
|
protected override Func<Quote, bool> HandleInteger(int value) {
|
|
|
|
|
return quote => quote.Game.Id == value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2011-02-26 01:22:07 +00:00
|
|
|
|
|
|
|
|
|
public virtual bool ShouldIndex { get; private set; }
|
2011-02-16 02:48:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class QuoteDto {
|
|
|
|
|
public int Id { get; set; }
|
|
|
|
|
public string Text { get; set; }
|
|
|
|
|
public GameDto Game { get; set; }
|
|
|
|
|
public DateTime Created { get; set; }
|
|
|
|
|
public IEnumerable<CategoryDto> Categories { get; set; }
|
|
|
|
|
public int TotalVotes { get; set; }
|
|
|
|
|
public int UpVotes { get; set; }
|
|
|
|
|
public int DownVotes { get; set; }
|
|
|
|
|
public int Score { get; set; }
|
2011-02-09 00:05:32 +00:00
|
|
|
|
}
|
2011-02-12 23:53:43 +00:00
|
|
|
|
|
|
|
|
|
public static class QuoteExtensions {
|
2011-02-14 07:39:45 +00:00
|
|
|
|
private static readonly Regex urlFriendlyRegex = new Regex(@"[^A-Za-z0-9_-]");
|
|
|
|
|
|
2011-02-27 04:20:59 +00:00
|
|
|
|
public static string FormatTextForHtml(this Quote quote) {
|
|
|
|
|
return HttpUtility.HtmlEncode(quote.Text).Replace("'", "’").Replace("\n", "<br />");
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 07:39:45 +00:00
|
|
|
|
public static string GetUrlFriendlyText(this Quote quote) {
|
|
|
|
|
var text = urlFriendlyRegex.Replace(quote.Text.Replace(" ", "_").Replace("\n", ""), "");
|
|
|
|
|
return text.Substring(0, Math.Min(text.Length, 50));
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-18 01:46:02 +00:00
|
|
|
|
public static string GetAbbreviatedText(this Quote quote) {
|
|
|
|
|
if (quote.Text.Length < 100) {
|
|
|
|
|
return quote.Text;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-19 09:41:09 +00:00
|
|
|
|
//ellipsis ftw
|
2011-02-18 01:46:02 +00:00
|
|
|
|
return quote.Text.Substring(0, 100) + Char.ConvertFromUtf32(0x2026);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-12 23:53:43 +00:00
|
|
|
|
public static string GetHumanReadableTimeSinceCreated(this Quote quote) {
|
|
|
|
|
var timespan = DateTime.UtcNow.Subtract(quote.Created);
|
|
|
|
|
if (timespan.TotalDays >= 365) {
|
|
|
|
|
var years = (int)Math.Round(timespan.TotalDays / 365);
|
|
|
|
|
return years == 1 ? "1 year ago" : years + " years ago";
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-28 01:03:49 +00:00
|
|
|
|
if (timespan.TotalDays >= 31) {
|
2011-02-12 23:53:43 +00:00
|
|
|
|
var months = (int)Math.Round(timespan.TotalDays / 30);
|
|
|
|
|
return months == 1 ? "1 month ago" : months + " months ago";
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-28 01:03:49 +00:00
|
|
|
|
if (timespan.TotalDays >= 7) {
|
2011-02-12 23:53:43 +00:00
|
|
|
|
var weeks = (int)Math.Round(timespan.TotalDays / 7);
|
|
|
|
|
return weeks == 1 ? "1 week ago" : weeks + " weeks ago";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (timespan.TotalDays >= 1) {
|
|
|
|
|
return (int)timespan.TotalDays == 1 ? "1 day ago" : (int)timespan.TotalDays + " days ago";
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-28 01:03:49 +00:00
|
|
|
|
if (timespan.TotalMinutes >= 60) {
|
2011-02-12 23:53:43 +00:00
|
|
|
|
return (int)timespan.TotalHours == 1 ? "1 hour ago" : (int)timespan.TotalHours + " hours ago";
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-28 01:03:49 +00:00
|
|
|
|
if (timespan.TotalSeconds >= 60) {
|
2011-02-12 23:53:43 +00:00
|
|
|
|
return (int)timespan.TotalMinutes == 1 ? "1 minute ago" : (int)timespan.TotalMinutes + " minutes ago";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int)timespan.TotalSeconds == 1 ? "1 second ago" : (int)timespan.TotalSeconds + " seconds ago";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 00:05:32 +00:00
|
|
|
|
}
|