394 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using gehGassi.Core.Interfaces;
using gehGassi.Domain.Common;
using gehGassi.Domain.Messages;
using gehGassi.Domain.News;
using Microsoft.EntityFrameworkCore;
namespace gehGassi.Core.Services
{
/// <summary>
/// Service der die Verwaltung von Konversationen und Nachrichten realisiert
/// </summary>
public class MessageService : ServiceBase<Message>, IMessageService
{
private readonly IRepository<Conversation> _conversationRepository;
private readonly IRepository<ConversationWithNames> _conversationNamesRepository;
private readonly IRepository<MessageCopy> _copyRepository;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="unitOfWork">Instanz eines IUnitOfWork</param>
public MessageService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_conversationRepository = unitOfWork.GetRepository<Conversation>();
_conversationNamesRepository = unitOfWork.GetRepository<ConversationWithNames>();
_copyRepository = unitOfWork.GetRepository<MessageCopy>();
}
/// <summary>
/// Gibt eine Liste der Konversationen eines Benutzers zurück
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// /// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste der Konversationen</returns>
public async Task<List<Conversation>> GetConversationsAsync(string senderId, DateTimeOffset? lastUpdate)
{
var query = _conversationRepository.Query(c => c.SenderId == senderId || c.ReceiverId == senderId);
if (lastUpdate.HasValue)
query = query.Where(c => c.UpdatedAt > lastUpdate);
return await query.ToListAsync().ConfigureAwait(false);
}
/// <summary>
/// Gibt eine Liste der Konversationen mit Namen aufgelöst eines Benutzers zurück
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <returns>Liste der Konversationen</returns>
public async Task<List<ConversationWithNames>> GetConversationsWithNamesAsync(string senderId)
{
var query = _conversationNamesRepository.Query(c => c.SenderId == senderId || c.ReceiverId == senderId);
return await query.ToListAsync().ConfigureAwait(false);
}
/// <summary>
/// Gibt eine Liste der Konversationen eines Benutzers zurück
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="filter">Filter der in Namen gesucht werden soll</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste der Konversationen</returns>
public async Task<List<Conversation>> GetConversationsAsync(string senderId, string filter, DateTimeOffset? lastUpdate)
{
var query = _conversationRepository.Query(c => c.SenderId == senderId || c.ReceiverId == senderId);
if (lastUpdate.HasValue)
query = query.Where(c => c.UpdatedAt > lastUpdate);
return await query.ToListAsync().ConfigureAwait(false);
}
/// <summary>
/// Gibt eine Konversation anhand der Teilnehmer zurück
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="receiverId">Id des Empfängers</param>
/// <returns>Konversation oder null wenn nicht gefunden</returns>
public async Task<Conversation> GetConversationAsync(string senderId, string receiverId)
{
var query = _conversationRepository.Query(c => (c.SenderId == senderId && c.ReceiverId == receiverId) || (c.SenderId == receiverId && c.ReceiverId == senderId));
var found = await query.FirstOrDefaultAsync().ConfigureAwait(false);
return found;
}
/// <summary>
/// Gibt eine gefilterte Liste von Konversationen mit Namen zurück
/// </summary>
/// <param name="filter">Filterbegriff der in bestimmten Feldern gesucht wird</param>
/// <returns>List betroffener Konversationen</returns>
public IQueryable<ConversationWithNames> FilterConversationsWithNames(string filter)
{
return _conversationNamesRepository.QueryView(c => c.SenderName.Contains(filter) || c.ReceiverName.Contains(filter));
}
/// <summary>
/// Hinzufügen einer Konversation
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="receiverId">Id des Empfängers</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
/// <returns>Konversation</returns>
public async Task<Conversation> AddConversationAsync(string senderId, string receiverId, string userName)
{
var conversation = new Conversation()
{
Id = Guid.NewGuid().ToString("N"),
Created = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow,
SenderId = senderId,
ReceiverId = receiverId,
LastMessage = null,
MessageCount = 0
};
_conversationRepository.Add(conversation);
await CommitAsync(userName).ConfigureAwait(false);
return conversation;
}
/// <summary>
/// Hinzufügen einer Konversation
/// </summary>
/// <param name="id">Id des Konversation</param>
/// <param name="senderId">Id des Senders</param>
/// <param name="receiverId">Id des Empfängers</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
/// <returns>Konversation</returns>
public async Task<Conversation> AddConversationAsync(string id, string senderId, string receiverId, string userName)
{
var conversation = new Conversation()
{
Id = id,
Created = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow,
SenderId = senderId,
ReceiverId = receiverId,
LastMessage = null,
MessageCount = 0
};
_conversationRepository.Add(conversation);
await CommitAsync(userName).ConfigureAwait(false);
return conversation;
}
/// <summary>
/// Entfernen einer Konversation
/// </summary>
/// <param name="id">Id der Konversation</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
public async Task<bool> RemoveConversationAsync(string id, string userName)
{
var conversation = await _conversationRepository.FirstOrDefaultAsync(c => c.Id == id).ConfigureAwait(false);
if (conversation != null)
{
_conversationRepository.Remove(conversation);
await CommitAsync(userName).ConfigureAwait(false);
return true;
}
return false;
}
/// <summary>
/// Entfernen einer Konversation nach AppUser
/// </summary>
/// <param name="appUserId">Id des AppUsers</param>
/// <returns>Anzahl Konversationen</returns>
public async Task<int> RemoveConversationByAppUserAsync(string appUserId)
{
var conversations = await Repository.FindAsync(c => c.ReceiverId == appUserId || c.SenderId == appUserId).ConfigureAwait(false);
foreach (var conversation in conversations)
{
Repository.Remove(conversation);
}
return conversations.Count();
}
/// <summary>
/// Gibt eine Liste noch nicht zugestellter Nachrichten für einen Benutzer zurück.
/// </summary>
/// <param name="senderId">Id des Users - wird als Receiver gesucht</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste nicht erhaltener Nachrichten</returns>
public async Task<List<Message>> GetMessagesAsync(string senderId, DateTimeOffset? lastUpdate)
{
var query = Repository.Query(c => c.ReceiverId == senderId);
if (lastUpdate.HasValue)
query = query.Where(c => c.UpdatedAt > lastUpdate);
return await query.ToListAsync().ConfigureAwait(false);
}
/// <summary>
/// Gibt eine Liste noch nicht zugestellter Nachrichten in einer Konversation für einen Benutzer zurück.
/// </summary>
/// <param name="senderId">Id des Users - wird als Receiver gesucht</param>
/// <param name="conversationId">Id der Konversation</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste nicht erhaltener Nachrichten</returns>
public async Task<List<Message>> GetMessagesAsync(string senderId, string conversationId, DateTimeOffset? lastUpdate)
{
var query = Repository.Query(c => c.ReceiverId == senderId && c.ConversationId == conversationId);
if (lastUpdate.HasValue)
query = query.Where(c => c.UpdatedAt > lastUpdate);
return await query.ToListAsync().ConfigureAwait(false);
}
/// <summary>
/// Berstätigen des Erhaltes von Nachrichten für einen Benutzer. Alle die älter als das UpdateDatum sind werden gelöscht
/// </summary>
/// <param name="senderId">Id des Users - wird als Receiver gesucht</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
/// <returns>true wenn erfolgreich, false sonst</returns>
public async Task<bool> ConfirmMessagesAsync(string senderId, DateTimeOffset lastUpdate, string userName)
{
var query = Repository.Query(c => c.ReceiverId == senderId && c.UpdatedAt <= lastUpdate);
var list = await query.ToListAsync().ConfigureAwait(false);
if (list.Any())
{
await SetMessageCopiesRead(list, DateTimeOffset.UtcNow).ConfigureAwait(false);
Repository.RemoveRange(list);
await CommitAsync(userName).ConfigureAwait(false);
}
return true;
}
/// <summary>
/// Berstätigen des Erhaltes von Nachrichten für eine Konversation für einen Benutzer. Alle die älter als das UpdateDatum sind werden gelöscht
/// </summary>
/// <param name="senderId">Id des Users - wird als Receiver gesucht</param>
/// <param name="conversationId">Id der Konversation</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
/// <returns>true wenn erfolgreich, false sonst</returns>
public async Task<bool> ConfirmMessagesAsync(string senderId, string conversationId, DateTimeOffset lastUpdate, string userName)
{
var query = Repository.Query(c => c.ReceiverId == senderId && c.ConversationId == conversationId && c.UpdatedAt <= lastUpdate);
var list = await query.ToListAsync().ConfigureAwait(false);
if (list.Any())
{
await SetMessageCopiesRead(list, DateTimeOffset.UtcNow).ConfigureAwait(false);
Repository.RemoveRange(list);
await CommitAsync(userName).ConfigureAwait(false);
}
return true;
}
/// <summary>
/// Hinzufügen einer Nachricht
/// </summary>
/// <param name="message">Nachricht</param>
/// <param name="userName">Benutzer der die Änderung vornimmt</param>
/// <returns>Angelegte Nachricht</returns>
public async Task<Message> AddMessageAsync(Message message, string userName)
{
Repository.Add(message);
var copy = new MessageCopy()
{
Id = message.Id,
Version = message.Version,
UpdatedAt = message.UpdatedAt,
Deleted = message.Deleted,
ConversationId = message.ConversationId,
SenderId = message.SenderId,
ReceiverId = message.ReceiverId,
Content = message.Content,
Read = false,
ReadDate = null
};
_copyRepository.Add(copy);
await CommitAsync(userName).ConfigureAwait(false);
return message;
}
/// <summary>
/// Neusetzen des UpdatedAt Datums falls sich das foto eines Benutzers geändert hat
/// </summary>
/// <param name="appUserId"></param>
/// <param name="updatedAt"></param>
/// <param name="userName"></param>
/// <returns></returns>
public async Task<int> SetUpdatedAtAsync(string appUserId, DateTimeOffset updatedAt, string userName)
{
var conversations = await _conversationRepository.FindAsync(c => (c.ReceiverId == appUserId || c.SenderId == appUserId )&& c.Deleted == false).ConfigureAwait(false);
foreach (var conversation in conversations)
{
conversation.UpdatedAt = updatedAt;
}
await CommitAsync(userName).ConfigureAwait(false);
return conversations.Count();
}
/// <summary>
/// Gibt die Anzahl der noch nicht gelesenen Nachrichten für einen Benutzer zurück
/// </summary>
/// <param name="receiverId">Id des Empfängers</param>
/// <param name="conversationId">Id der Konversation</param>
/// <returns>Anzahl ungelesene Nachrichten</returns>
public async Task<int> CountOpenMessagesAsync(string receiverId, string conversationId)
{
var messageCount = await Repository.Query(m => m.ReceiverId == receiverId && m.ConversationId == conversationId).CountAsync().ConfigureAwait(false);
return messageCount;
}
/// <summary>
/// Entfernt Nachrichten die in einem bestimmten Zeitraum nicht gelesen wurden
/// </summary>
/// <param name="olderThanDate">Nachricht muss älter als dieses Datum sein</param>
/// <returns>Anzahl gelöschte Nachrichten</returns>
public async Task<int> RemoveUnreadMessagesAsync(DateTimeOffset olderThanDate)
{
var messages = await Repository.FindAsync(c => c.UpdatedAt < olderThanDate);
foreach (var message in messages)
{
Repository.Remove(message);
}
return messages.Count();
}
/// <summary>
/// Entfernt Nachrichten-Kopien die alter als ein Datum sind
/// </summary>
/// <param name="olderThanDate">Nachricht muss älter als dieses Datum sein</param>
/// <returns>Anzahl gelöschte Nachrichten</returns>
public async Task<int> RemoveMessageCopiesAsync(DateTimeOffset olderThanDate)
{
var messages = await _copyRepository.FindAsync(c => c.UpdatedAt < olderThanDate);
foreach (var message in messages)
{
_copyRepository.Remove(message);
}
return messages.Count();
}
/// <summary>
/// Gibt die Nachrichten-Kopien einer Konversation zurück
/// </summary>
/// <param name="conversationId">Id der Konversation</param>
/// <returns>Liste nicht erhaltener Nachrichten</returns>
public async Task<List<MessageCopy>> GetMessageCopiesAsync(string conversationId)
{
var messages = (await _copyRepository.FindAsync(c => c.ConversationId == conversationId).ConfigureAwait(false)).OrderBy(c => c.UpdatedAt).ToList();
return messages;
}
#region private
/// <summary>
/// Setzt die Kopiene einer Liste von Nachrichten auf gelesen
/// </summary>
/// <param name="messages">Liste der Nachrichten</param>
/// <param name="readDate">Datum gelesen</param>
/// <returns>Task</returns>
private async Task SetMessageCopiesRead(List<Message> messages, DateTimeOffset readDate)
{
foreach (var message in messages)
{
var copy = await _copyRepository.GetAsync(message.Id);
if (copy != null)
{
copy.Read = true;
copy.ReadDate = readDate;
}
}
}
#endregion
}
}