using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Asp.Versioning;
using AutoMapper;
using gehGassi.Core.Interfaces;
using gehGassi.Core.Services;
using gehGassi.Domain.Common;
using gehGassi.Domain.Dogs;
using gehGassi.Domain.Messages;
using gehGassi.Domain.Pushnotifications;
using gehGassi.Dto;
using gehGassi.Dto.Common;
using gehGassi.Dto.Favourites;
using gehGassi.Dto.Messages;
using gehGassi.Web.Auth;
using gehGassi.Web.Hubs;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using LocalizationOptions = gehGassi.Web.Helper.LocalizationOptions;
namespace gehGassi.Web.Controllers.Api
{
///
/// Controller der Zugriff auf Nachrichten via API ermöglicht
///
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[ApiVersion(1)]
[Route("api/messages")]
[Route("api/v{v:apiVersion}/messages")]
public class ApiMessagesController : ApiBaseController
{
private readonly ILogger _logger;
private readonly IMessageService _messageService;
private readonly IAppHubSender _appHubSender;
private readonly ISystemMessageService _systemMessageService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IDeviceService _deviceService;
private readonly IStringLocalizer _localizer;
private readonly IUserOnlineService _userOnlineService;
///
/// Erstellt eine Instanz
///
/// Instanz eines IMapper
/// Instanz eines ILogger
/// Instanz von LocalizationOptions
/// Instanz eines IDogOwnerService
/// Instanz eines IMessageService
/// Instanz eines IAppHubSender
///
/// Instanz eines IPushNotificationService
/// Instanz eines IDeviceService
/// Instanz eines IStringLocalizer
/// Instanz eines IUserOnlineService
public ApiMessagesController(IMapper mapper, ILogger logger, IOptions localizationOptions, IAppUserService appUserService,
IMessageService messageService, IAppHubSender appHubSender, ISystemMessageService systemMessageService, IPushNotificationService pushNotificationService,
IDeviceService deviceService, IStringLocalizer localizer, IUserOnlineService userOnlineService) : base(mapper, localizationOptions, appUserService)
{
_logger = logger;
_messageService = messageService;
_appHubSender = appHubSender;
_systemMessageService = systemMessageService;
_pushNotificationService = pushNotificationService;
_deviceService = deviceService;
_localizer = localizer;
_userOnlineService = userOnlineService;
}
///
/// Anlegen einer Konversation
///
/// CreateConversationDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("CreateConversation")]
public async Task CreateConversation(CreateConversationDto model)
{
var clientOffset = GetClientDateOffset();
var result = new CreateResponseDto
{
Status = CreateStatusDto.Error,
Value = null
};
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
if (model.SenderId != model.ReceiverId)
{
//Wenn Sender und Emfpägner nicht gleich sind!
var otherId = string.Empty;
//Prüfen ob es die Konversation schon gibt...
var conversation = await _messageService.GetConversationAsync(model.SenderId, model.ReceiverId);
if (conversation == null)
{
conversation = await _messageService.AddConversationAsync(model.Id, model.SenderId, model.ReceiverId, User.Identity.Name);
result.Status = CreateStatusDto.Success;
result.Value = Mapper.Map(conversation);
otherId = model.ReceiverId;
}
else
{
result.Status = CreateStatusDto.Exists;
result.Value = Mapper.Map(conversation);
if (model.SenderId == conversation.SenderId)
{
otherId = model.ReceiverId;
}
else
{
otherId = model.SenderId;
}
}
var baseAddress = GetBaseAddress();
var appUser = await AppUserService.GetAsync(otherId);
result.Value.ReceipientType = (AppUserTypeDto)appUser.Type;
result.Value.Recipient = appUser.Id;
result.Value.RecipientName = $"{appUser.FirstName} {appUser.LastName}";
result.Value.RecipientShort = GetInitials(appUser.FirstName, appUser.LastName);
result.Value.RecipientPhoto = !string.IsNullOrWhiteSpace(appUser.Photo) ? $"{baseAddress}/file/documents/thumbnails/{100}/{appUser.Photo}" : "";
return Ok(result);
}
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Abfragen der Konversationen eines Users
///
/// Id des Senders
/// Letztes Update
/// Liste der Konversationen
[HttpGet]
[Route("GetConversations")]
public async Task GetConversations(string senderId, DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var conversations = await _messageService.GetConversationsAsync(senderId, lastUpdate);
var conversationDtoList = Mapper.Map>(conversations);
var baseAddress = GetBaseAddress();
foreach (var item in conversationDtoList)
{
var otherId = string.Empty;
var conversation = conversations.First(c => c.Id == item.Id);
if (conversation.SenderId == senderId)
{
otherId = conversation.ReceiverId;
}
else
{
otherId = conversation.SenderId;
}
var appUser = await AppUserService.GetAsync(otherId);
item.ReceipientType = (AppUserTypeDto)appUser.Type;
item.Recipient = appUser.Id;
item.RecipientName = $"{appUser.FirstName} {appUser.LastName}";
item.RecipientShort = GetInitials(appUser.FirstName, appUser.LastName);
item.RecipientPhoto = !string.IsNullOrWhiteSpace(appUser.Photo) ? $"{baseAddress}/file/documents/thumbnails/{100}/{appUser.Photo}" : "";
}
return Ok(conversationDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Abfragen der Konversationen eines Users
///
/// Id des Senders
/// Filterwert der in Namen gesucht wird
/// Liste der Konversationen
[HttpGet]
[Route("GetConversationsEx")]
public async Task GetConversationsEx(string senderId, string filter)
{
var clientOffset = GetClientDateOffset();
filter ??= string.Empty;
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var conversations = await _messageService.GetConversationsWithNamesAsync(senderId);
var conversationList = new List();
foreach (var conversation in conversations)
{
if (conversation.SenderId == senderId)
{
if (!conversation.ReceiverBlocked && !conversation.ReceiverLocked && conversation.ReceiverName.Contains(filter))
conversationList.Add(conversation);
}
else
{
if (!conversation.SenderBlocked && !conversation.SenderLocked && conversation.SenderName.Contains(filter))
conversationList.Add(conversation);
}
}
var conversationDtoList = Mapper.Map>(conversationList);
var baseAddress = GetBaseAddress();
foreach (var item in conversationDtoList)
{
var conversation = conversationList.First(c => c.Id == item.Id);
if (conversation.SenderId == senderId)
{
item.ReceipientType = (AppUserTypeDto)conversation.ReceiverType;
item.Recipient = conversation.ReceiverId;
item.RecipientName = conversation.ReceiverName;
item.RecipientShort = GetInitials(conversation.ReceiverFirstName, conversation.ReceiverLastName);
item.RecipientPhoto = !string.IsNullOrWhiteSpace(conversation.ReceiverPhoto) ? $"{baseAddress}/file/documents/thumbnails/{100}/{conversation.ReceiverPhoto}" : "";
}
else
{
item.ReceipientType = (AppUserTypeDto)conversation.SenderType;
item.Recipient = conversation.SenderId;
item.RecipientName = conversation.SenderName;
item.RecipientShort = GetInitials(conversation.SenderFirstName, conversation.SenderLastName);
item.RecipientPhoto = !string.IsNullOrWhiteSpace(conversation.SenderPhoto) ? $"{baseAddress}/file/documents/thumbnails/{100}/{conversation.SenderPhoto}" : "";
}
}
return Ok(conversationDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Abfragen der Konversationen eines Benutzers mit einem Emüfänger
///
/// Id des Senders
/// Id des Empfängers nach dem gesucht wird
/// Konversationen oder NotFound wenn nicht gefunden
[HttpGet]
[Route("GetConversationByReceipient")]
public async Task GetConversationByReceipient(string senderId, string receipientId)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var conversation = await _messageService.GetConversationAsync(senderId, receipientId);
if (conversation != null)
{
var baseAddress = GetBaseAddress();
var otherId = string.Empty;
if (conversation.SenderId == senderId)
{
otherId = conversation.ReceiverId;
}
else
{
otherId = conversation.SenderId;
}
var item = Mapper.Map(conversation);
var appUser = await AppUserService.GetAsync(otherId);
item.ReceipientType = (AppUserTypeDto)appUser.Type;
item.Recipient = appUser.Id;
item.RecipientName = $"{appUser.FirstName} {appUser.LastName}";
item.RecipientShort = GetInitials(appUser.FirstName, appUser.LastName);
item.RecipientPhoto = !string.IsNullOrWhiteSpace(appUser.Photo) ? $"{baseAddress}/file/documents/thumbnails/{100}/{appUser.Photo}" : "";
return Ok(item);
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Abfragen der bisher noch nicht abgerufenen Nachrichten für einen Benutzer
///
/// Id des Senders - gilt dann als Empfänger
/// Letztes Update
/// Liste Nachrichten
[HttpGet]
[Route("GetMessages")]
public async Task GetMessages(string senderId, DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var messages = await _messageService.GetMessagesAsync(senderId, lastUpdate);
var messagesDtoList = Mapper.Map>(messages);
return Ok(messagesDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Abfragen der bisher noch nicht abgerufenen Nachrichten für einen Benutzer in einer Konversation
///
/// Id des Senders - gilt dann als Empfänger
/// Id der Konversation
/// Letztes Update
/// Liste Nachrichten
[HttpGet]
[Route("GetMessagesByConversation")]
public async Task GetMessagesByConversation(string senderId, string conversationId, DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var messages = await _messageService.GetMessagesAsync(senderId, conversationId, lastUpdate);
var messagesDtoList = Mapper.Map>(messages);
return Ok(messagesDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Bestätigen des erfolgreichen Erhalts von Nachrichten
///
/// MessageConfirmationDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("ConfirmMessages")]
public async Task ConfirmMessages(MessageConfirmationDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
await _messageService.ConfirmMessagesAsync(model.SenderId, model.LastUpdate.Value, User.Identity.Name);
return Ok();
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Bestätigen des erfolgreichen Erhalts von Nachrichten für eine Konversation
///
/// MessageConfirmationDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("ConfirmMessagesByConversation")]
public async Task ConfirmMessagesByConversation(MessageConfirmationDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
await _messageService.ConfirmMessagesAsync(model.SenderId, model.ConversationId, model.LastUpdate.Value, User.Identity.Name);
return Ok();
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Hinzufügen einer Nachricht zu einer Konversation
///
/// MessageDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("AddMessage")]
public async Task AddMessage(MessageDto model)
{
var clientOffset = GetClientDateOffset();
var result = new CreateResponseDto
{
Status = CreateStatusDto.Error,
Value = null
};
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var appUserId = User.AppUserId();
var isLocked = await AppUserService.IsLockedAsync(appUserId);
var isBlocked = await AppUserService.IsBlockedAsync(model.ReceiverId, model.SenderId);
var message = Mapper.Map(model);
var existingMessage = await _messageService.GetAsync(message.Id);
if (existingMessage == null && !isLocked && !isBlocked)
{
message = await _messageService.AddMessageAsync(message, User.Identity.Name);
var conversation = await _messageService.GetConversationAsync(message.SenderId, message.ReceiverId);
if (conversation != null)
{
conversation.MessageCount += 1;
conversation.LastMessage = DateTimeOffset.UtcNow;
await _messageService.CommitAsync(User.Identity.Name);
}
result.Status = CreateStatusDto.Success;
result.Value = model;
await _appHubSender.MessageAddedAsync(model.ReceiverId);
var isOnline = await _userOnlineService.IsAppUserOnlineAsync(model.ReceiverId);
if (!isOnline)
{
//Pushnotification nur senden, wenn es sich um eine offene Nachricht handelt
var openMessageCount = await _messageService.CountOpenMessagesAsync(model.ReceiverId, model.ConversationId);
if (openMessageCount == 1)
{
var success = await _pushNotificationService.SendNewMessageAsync(model.ReceiverId, model.ConversationId);
}
}
}
return Ok(result);
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
#region Systemmessages
///
/// Abfrage der Systemnachrichten eines AppUsers
///
/// Id des AppUsers
/// Letztes Update oder null, wenn noch keines
/// Liste der Favoriten
[HttpGet]
[Route("GetSystemMessagesForSync")]
public async Task GetSystemMessagesForSync(string appUserId, DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var systemMessages = await _systemMessageService.GetForSyncAppAsync(appUserId, lastUpdate);
var dtoList = Mapper.Map>(systemMessages);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Bestätigen des erfolgreichen Erhalts von Systemnachrichten
///
/// SystemMessageConfirmationDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("ConfirmSystemMessages")]
public async Task ConfirmSystemMessages(SystemMessageConfirmationDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
await _systemMessageService.ConfirmAsync(model.SenderId, model.LastUpdate.Value, User.Identity.Name);
return Ok();
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Löschen von Systemnachrichten für einen AppUser wenn die Details in der App schon verfügbar sind
///
/// SystemMessageRemoveDto
/// HTTP 200 OK, Felher sonst
[HttpPost]
[Route("RemoveSystemMessages")]
public async Task RemoveSystemMessages(SystemMessageRemoveDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
await _systemMessageService.RemoveAsync(model.AppUserId, (AppUserType)model.AppUserType, model.Key, model.Table, model.Created, User.Identity.Name);
return Ok();
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
#endregion
#region Helper
///
/// Hilfsmethode zum erstellen der Initialen aus Vor- und Nachname
///
/// Vorname
/// Nachname
/// Initialen
private string GetInitials(string firstName, string lastName)
{
if (!string.IsNullOrWhiteSpace(firstName) && !string.IsNullOrWhiteSpace(lastName))
return $"{firstName.Substring(0, 1)}{lastName.Substring(0, 1)}";
else if (!string.IsNullOrWhiteSpace(firstName) && firstName.Length >= 2 && string.IsNullOrWhiteSpace(lastName))
return $"{firstName.Substring(0, 2)}";
else if (string.IsNullOrWhiteSpace(firstName) && string.IsNullOrWhiteSpace(lastName) && lastName.Length >= 2)
return $"{lastName.Substring(0, 2)}";
else
return "??";
}
#endregion
}
}