vgquotes/Src/VideoGameQuotes.Api/Quote.cs

191 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Iesi.Collections.Generic;
using Portoa.Persistence;
namespace VideoGameQuotes.Api {
public class Quote : Entity<Quote, int>, IDtoMappable<QuoteDto> {
private readonly Iesi.Collections.Generic.ISet<Vote> votes = new HashedSet<Vote>();
private readonly Iesi.Collections.Generic.ISet<QuoteFlag> flags = new HashedSet<QuoteFlag>();
private readonly Iesi.Collections.Generic.ISet<Category> categories = new HashedSet<Category>();
public Quote() {
Created = DateTime.UtcNow;
}
public virtual User Creator { get; set; }
public virtual DateTime Created { get; set; }
public virtual DateTime? Modified { get; set; }
public virtual string Text { get; set; }
public virtual Game Game { get; set; }
public virtual IEnumerable<Vote> Votes { get { return votes; } }
public virtual IEnumerable<QuoteFlag> Flags { get { return flags; } }
public virtual IEnumerable<Category> Categories { get { return categories; } }
#region adding and removing stuff
public virtual Quote AddCategory(Category category) {
categories.Add(category);
return this;
}
public virtual void ClearCategories() {
categories.Clear();
}
public virtual Quote AddFlag(string comment, QuoteFlagType type, User user) {
flags.Add(new QuoteFlag {
Comment = comment,
Type = type,
User = user,
Quote = this
});
return this;
}
public virtual Quote RemoveFlag(QuoteFlag flag) {
flags.Remove(flag);
return this;
}
public virtual void ClearFlags() {
flags.Clear();
}
#endregion
public virtual Quote VoteFor(User user, VoteDirection direction) {
var currentVote = votes.SingleOrDefault(vote => vote.Voter == user);
if (currentVote != null) {
if (currentVote.Direction == direction) {
throw new CannotVoteTwiceException();
}
votes.Remove(currentVote);
if (currentVote.Direction == VoteDirection.Up) {
UpVotes--;
} else {
DownVotes--;
}
currentVote.Direction = direction;
currentVote.Created = DateTime.UtcNow;
votes.Add(currentVote);
} else {
votes.Add(new Vote { Direction = direction, Quote = this, Voter = user });
}
if (direction == VoteDirection.Up) {
UpVotes++;
} else {
DownVotes++;
}
Score = UpVotes - DownVotes;
return this;
}
public virtual VoteDirection? VotedFor(User user) {
var vote = Votes.Where(v => v.Voter == user).SingleOrDefault();
if (vote == null) {
return null;
}
return vote.Direction;
}
public virtual int UpVotes { get; private set; }
public virtual int DownVotes { get; private set; }
public virtual int Score { get; private set; }
public virtual QuoteDto ToDto() {
return new QuoteDto {
Id = Id,
Text = Text,
Game = Game.ToDto(),
Created = Created,
Categories = Categories.Select(category => category.ToDto()),
TotalVotes = Votes.Count(),
UpVotes = UpVotes,
DownVotes = DownVotes,
Score = Score
};
}
#region nested types
public class GameCriterionHandler : CriterionHandler<Quote> {
protected override Func<Quote, bool> HandleInteger(int value) {
return quote => quote.Game.Id == value;
}
}
#endregion
}
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; }
}
public static class QuoteExtensions {
private static readonly Regex urlFriendlyRegex = new Regex(@"[^A-Za-z0-9_-]");
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));
}
public static string GetAbbreviatedText(this Quote quote) {
if (quote.Text.Length < 100) {
return quote.Text;
}
//ellipsis ftw
return quote.Text.Substring(0, 100) + Char.ConvertFromUtf32(0x2026);
}
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";
}
if (timespan.TotalDays >= 50) {
var months = (int)Math.Round(timespan.TotalDays / 30);
return months == 1 ? "1 month ago" : months + " months ago";
}
if (timespan.TotalDays >= 10) {
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";
}
if (timespan.TotalMinutes >= 90) {
return (int)timespan.TotalHours == 1 ? "1 hour ago" : (int)timespan.TotalHours + " hours ago";
}
if (timespan.TotalSeconds >= 90) {
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";
}
}
}