public void Send(string messagesUrl, UserMessage message)
        {
            ParamIs.NotNull(() => message);

            if (string.IsNullOrEmpty(message.Receiver.Email))
                return;

            MailAddress to;

            try {
                to = new MailAddress(message.Receiver.Email);
            } catch (FormatException x) {
                log.WarnException("Unable to validate receiver email", x);
                return;
            }

            var mailMessage = new MailMessage();
            mailMessage.To.Add(to);
            mailMessage.Subject = "New private message from " + message.Sender.Name;
            mailMessage.Body =
                "Hi " + message.Receiver.Name + ",\n\n" +
                "You have received a message from " + message.Sender.Name + ".\n" +
                "You can view your messages at " + messagesUrl + " and decline from receiving any future messages by changing your settings.\n\n" +
                "- VocaDB mailer";

            var client = new SmtpClient();

            try {
                client.Send(mailMessage);
            } catch (SmtpException x) {
                log.ErrorException("Unable to send mail", x);
            }
        }
		public void CheckComment(Comment comment, IEntryLinkFactory entryLinkFactory, IRepositoryContext<User> ctx) {

			var userMatches = Regex.Match(comment.Message, @"@(\w+)");

			if (!userMatches.Success)
				return;

			var userNames = userMatches.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray();

			var users = ctx.Query().Where(u => u.Active && userNames.Contains(u.Name)).ToArray();

			if (!users.Any())
				return;

			var commentMsg = comment.Message.Truncate(200);
			var msg = string.Format("{0} mentioned you in a comment for {1}\n\n{2}", comment.AuthorName, MarkdownHelper.CreateMarkdownLink(entryLinkFactory.GetFullEntryUrl(comment.Entry), comment.Entry.DefaultName), commentMsg);

			foreach (var user in users) {

				var notification = new UserMessage(user, "Mentioned in a comment", msg, false);
				ctx.OfType<UserMessage>().Save(notification);

			}

		}
        public UserMessageContract(UserMessage message)
        {
            ParamIs.NotNull(() => message);

            Body = message.Message;
            Created = message.Created;
            HighPriority = message.HighPriority;
            Id = message.Id;
            Read = message.Read;
            Receiver = new UserContract(message.Receiver);
            Sender = new UserContract(message.Sender);
            Subject = message.Subject;
        }
		public UserMessageContract(UserMessage message, IUserIconFactory iconFactory, bool includeBody = false) {

			ParamIs.NotNull(() => message);

			Body = (includeBody ? message.Message : string.Empty);
			Created = message.Created;
			CreatedFormatted = Created.ToUniversalTime().ToString("g");
			HighPriority = message.HighPriority;
			Id = message.Id;
			Read = message.Read;
			Receiver = new UserWithIconContract(message.Receiver, iconFactory);
			Sender = (message.Sender != null ? new UserWithIconContract(message.Sender, iconFactory) : null);
			Subject = message.Subject;

		}
		public void SendPrivateMessageNotification(string mySettingsUrl, string messagesUrl, UserMessage message) {

			ParamIs.NotNull(() => message);

			var subject = string.Format("New private message from {0}", message.Sender.Name);
			var body = string.Format(
				"You have received a message from {0}. " +
				"You can view your messages at {1}." +
				"\n\n" +
				"If you do not wish to receive more email notifications such as this, you can adjust your settings at {2}.", 
				message.Sender.Name, messagesUrl, mySettingsUrl);

			SendEmail(message.Receiver.Email, message.Receiver.Name, subject, body);

		}
		public void SetUp() {
			
			sender = new User { Name = "Sender user", Id = 1};
			receiver = new User { Name = "Receiver user", Id = 2 };
			permissionContext = new FakePermissionContext(new UserWithPermissionsContract(receiver, ContentLanguagePreference.Default));

			receivedMessage = CreateEntry.UserMessage(id: 1, sender: sender, receiver: receiver, subject: "Hello world", body: "Message body", read: true);
			sentMessage = CreateEntry.UserMessage(id: 2, sender: receiver, receiver: sender, subject: "Hello to you too", body: "Message body");
			var noPermissionMessage = CreateEntry.UserMessage(id: 39, sender: sender, receiver: sender, subject: "Hello world", body: "Message body");

			repository = new FakeUserMessageRepository(sentMessage, receivedMessage, noPermissionMessage);

			queries = new UserMessageQueries(repository, permissionContext);

		}
		/// <summary>
		/// Sends notifications
		/// </summary>
		/// <param name="ctx">Repository context. Cannot be null.</param>
		/// <param name="entry">Entry that was created. Cannot be null.</param>
		/// <param name="artists">List of artists for the entry. Cannot be null.</param>
		/// <param name="creator">User who created the entry. The creator will be excluded from all notifications. Cannot be null.</param>
		/// <param name="entryLinkFactory">Factory for creating links to entries. Cannot be null.</param>
		/// <param name="mailer">Mailer for user email messages. Cannot be null.</param>
		public void SendNotifications(IRepositoryContext<UserMessage> ctx, IEntryWithNames entry, 
			IEnumerable<Artist> artists, IUser creator, IEntryLinkFactory entryLinkFactory,
			IUserMessageMailer mailer) {

			ParamIs.NotNull(() => ctx);
			ParamIs.NotNull(() => entry);
			ParamIs.NotNull(() => artists);
			ParamIs.NotNull(() => creator);
			ParamIs.NotNull(() => entryLinkFactory);
			ParamIs.NotNull(() => mailer);

			var coll = artists.ToArray();
			var artistIds = coll.Select(a => a.Id).ToArray();

			// Get users with 3 or less unread messages, following any of the artists
			var usersWithArtists = ctx.OfType<ArtistForUser>()
				.Query()
				.Where(afu => 
					artistIds.Contains(afu.Artist.Id) 
					&& afu.User.Id != creator.Id && afu.User.Active
					&& afu.SiteNotifications
					&& afu.User.ReceivedMessages.Count(m => !m.Read) <= 9)
				.Select(afu => new {
					UserId = afu.User.Id, 
					ArtistId = afu.Artist.Id
				})
				.ToArray()
				.GroupBy(afu => afu.UserId)
				.ToDictionary(afu => afu.Key, afu => afu.Select(a => a.ArtistId));

			var userIds = usersWithArtists.Keys;

			if (!userIds.Any())
				return;

			var users = ctx.OfType<User>().Query().Where(u => userIds.Contains(u.Id)).ToArray();

			foreach (var user in users) {

				var artistIdsForUser = new HashSet<int>(usersWithArtists[user.Id]);
				var followedArtists = coll.Where(a => artistIdsForUser.Contains(a.Id)).ToArray();

				if (followedArtists.Length == 0)
					continue;

				string title;

				var entryTypeName = entry.EntryType.ToString().ToLowerInvariant();
				var msg = CreateMessageBody(followedArtists, user, entry, entryLinkFactory, true);

				if (followedArtists.Length == 1) {

					var artistName = followedArtists.First().TranslatedName[user.DefaultLanguageSelection];
					title = string.Format("New {0} by {1}", entryTypeName, artistName);

				} else {

					title = string.Format("New {0}", entryTypeName);

				}

				var notification = new UserMessage(user, title, msg, false);
				ctx.Save(notification);

				if (user.EmailOptions != UserEmailOptions.NoEmail && !string.IsNullOrEmpty(user.Email) 
					&& followedArtists.Any(a => a.Users.Any(u => u.User.Equals(user) && u.EmailNotifications))) {
					
					mailer.SendEmail(user.Email, user.Name, title, CreateMessageBody(followedArtists, user, entry, entryLinkFactory, false));

				}

			}

		}