gehgassi_backend/gehGassi.Web/Controllers/Api/ApiMessagesController.cs

547 lines
20 KiB
C#

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
{
/// <summary>
/// Controller der Zugriff auf Nachrichten via API ermöglicht
/// </summary>
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[ApiVersion(1)]
[Route("api/messages")]
[Route("api/v{v:apiVersion}/messages")]
public class ApiMessagesController : ApiBaseController
{
private readonly ILogger<ApiMessagesController> _logger;
private readonly IMessageService _messageService;
private readonly IAppHubSender _appHubSender;
private readonly ISystemMessageService _systemMessageService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IDeviceService _deviceService;
private readonly IStringLocalizer<ApiMessagesController> _localizer;
private readonly IUserOnlineService _userOnlineService;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="mapper">Instanz eines IMapper</param>
/// <param name="logger">Instanz eines ILogger</param>
/// <param name="localizationOptions">Instanz von LocalizationOptions</param>
/// <param name="appUserService">Instanz eines IDogOwnerService</param>
/// <param name="messageService">Instanz eines IMessageService</param>
/// <param name="appHubSender">Instanz eines IAppHubSender</param>
/// <param name="systemMessageService"></param>
/// <param name="pushNotificationService">Instanz eines IPushNotificationService</param>
/// <param name="deviceService">Instanz eines IDeviceService</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="userOnlineService">Instanz eines IUserOnlineService</param>
public ApiMessagesController(IMapper mapper, ILogger<ApiMessagesController> logger, IOptions<LocalizationOptions> localizationOptions, IAppUserService appUserService,
IMessageService messageService, IAppHubSender appHubSender, ISystemMessageService systemMessageService, IPushNotificationService pushNotificationService,
IDeviceService deviceService, IStringLocalizer<ApiMessagesController> localizer, IUserOnlineService userOnlineService) : base(mapper, localizationOptions, appUserService)
{
_logger = logger;
_messageService = messageService;
_appHubSender = appHubSender;
_systemMessageService = systemMessageService;
_pushNotificationService = pushNotificationService;
_deviceService = deviceService;
_localizer = localizer;
_userOnlineService = userOnlineService;
}
/// <summary>
/// Anlegen einer Konversation
/// </summary>
/// <param name="model">CreateConversationDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("CreateConversation")]
public async Task<IActionResult> CreateConversation(CreateConversationDto model)
{
var clientOffset = GetClientDateOffset();
var result = new CreateResponseDto<ConversationDto>
{
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<ConversationDto>(conversation);
otherId = model.ReceiverId;
}
else
{
result.Status = CreateStatusDto.Exists;
result.Value = Mapper.Map<ConversationDto>(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);
}
/// <summary>
/// Abfragen der Konversationen eines Users
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste der Konversationen</returns>
[HttpGet]
[Route("GetConversations")]
public async Task<IActionResult> 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<List<ConversationDto>>(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);
}
/// <summary>
/// Abfragen der Konversationen eines Users
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="filter">Filterwert der in Namen gesucht wird</param>
/// <returns>Liste der Konversationen</returns>
[HttpGet]
[Route("GetConversationsEx")]
public async Task<IActionResult> 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<ConversationWithNames>();
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<List<ConversationDto>>(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);
}
/// <summary>
/// Abfragen der Konversationen eines Benutzers mit einem Emüfänger
/// </summary>
/// <param name="senderId">Id des Senders</param>
/// <param name="receipientId">Id des Empfängers nach dem gesucht wird</param>
/// <returns>Konversationen oder NotFound wenn nicht gefunden</returns>
[HttpGet]
[Route("GetConversationByReceipient")]
public async Task<IActionResult> 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<ConversationDto>(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);
}
/// <summary>
/// Abfragen der bisher noch nicht abgerufenen Nachrichten für einen Benutzer
/// </summary>
/// <param name="senderId">Id des Senders - gilt dann als Empfänger</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste Nachrichten</returns>
[HttpGet]
[Route("GetMessages")]
public async Task<IActionResult> 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<List<MessageDto>>(messages);
return Ok(messagesDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Abfragen der bisher noch nicht abgerufenen Nachrichten für einen Benutzer in einer Konversation
/// </summary>
/// <param name="senderId">Id des Senders - gilt dann als Empfänger</param>
/// <param name="conversationId">Id der Konversation</param>
/// <param name="lastUpdate">Letztes Update</param>
/// <returns>Liste Nachrichten</returns>
[HttpGet]
[Route("GetMessagesByConversation")]
public async Task<IActionResult> 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<List<MessageDto>>(messages);
return Ok(messagesDtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Bestätigen des erfolgreichen Erhalts von Nachrichten
/// </summary>
/// <param name="model">MessageConfirmationDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("ConfirmMessages")]
public async Task<IActionResult> 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);
}
/// <summary>
/// Bestätigen des erfolgreichen Erhalts von Nachrichten für eine Konversation
/// </summary>
/// <param name="model">MessageConfirmationDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("ConfirmMessagesByConversation")]
public async Task<IActionResult> 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);
}
/// <summary>
/// Hinzufügen einer Nachricht zu einer Konversation
/// </summary>
/// <param name="model">MessageDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("AddMessage")]
public async Task<IActionResult> AddMessage(MessageDto model)
{
var clientOffset = GetClientDateOffset();
var result = new CreateResponseDto<MessageDto>
{
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<Message>(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
/// <summary>
/// Abfrage der Systemnachrichten eines AppUsers
/// </summary>
/// <param name="appUserId">Id des AppUsers</param>
/// <param name="lastUpdate">Letztes Update oder null, wenn noch keines</param>
/// <returns>Liste der Favoriten</returns>
[HttpGet]
[Route("GetSystemMessagesForSync")]
public async Task<IActionResult> 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<List<SystemMessageDto>>(systemMessages);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Bestätigen des erfolgreichen Erhalts von Systemnachrichten
/// </summary>
/// <param name="model">SystemMessageConfirmationDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("ConfirmSystemMessages")]
public async Task<IActionResult> 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);
}
/// <summary>
/// Löschen von Systemnachrichten für einen AppUser wenn die Details in der App schon verfügbar sind
/// </summary>
/// <param name="model">SystemMessageRemoveDto</param>
/// <returns>HTTP 200 OK, Felher sonst</returns>
[HttpPost]
[Route("RemoveSystemMessages")]
public async Task<IActionResult> 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
/// <summary>
/// Hilfsmethode zum erstellen der Initialen aus Vor- und Nachname
/// </summary>
/// <param name="firstName">Vorname</param>
/// <param name="lastName">Nachname</param>
/// <returns>Initialen</returns>
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
}
}