using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Sozsoft.Notifications.Domain;
using Sozsoft.Notifications.Entities;
using Sozsoft.Notifications.Enums;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
namespace Sozsoft.Notifications.Application;
///
/// Kullanicinin kendi bildirimleri: liste, okundu isaretleme ve tarayici kanallarinda gosterim
/// isareti. Her sorgu UserId ile kendi kayitlarina kapalidir.
///
[Authorize]
public class NotificationAppService : ReadOnlyAppService<
Notification,
NotificationDto,
Guid,
NotificationFilterRequestDto>
{
private readonly IRepository repository;
private readonly IRepository repositoryRule;
private readonly INotificationManager notificationManager;
private readonly IRepository repositoryUser;
public NotificationAppService(
IRepository repository,
IRepository repositoryRule,
INotificationManager notificationManager,
IRepository repositoryUser) : base(repository)
{
this.repository = repository;
this.repositoryRule = repositoryRule;
this.notificationManager = notificationManager;
this.repositoryUser = repositoryUser;
}
/// Bir kuraldan elle bildirim uretir; Bildirim Kurallari ekranindaki "Create" komutu.
public async Task CreateNotificationByNotificationRuleIdAsync(NotificationRequestDto input)
{
var notificationRule = await repositoryRule.FindAsync(input.Id)
?? throw new EntityNotFoundException(L["RecordNotFound"]);
await notificationManager.SendNotificationAsync(notificationRule.NotificationTypeId, input.Message);
}
protected override async Task> CreateFilteredQueryAsync(NotificationFilterRequestDto input)
{
var query = await base.CreateFilteredQueryAsync(input);
input.Channels ??= [];
var now = Clock.Now.AddDays(-1);
query = query
.AsNoTracking()
.Include(a => a.NotificationType)
.Where(a => a.UserId == CurrentUser.Id)
.Where(a => input.Channels.Contains(a.NotificationChannel))
.WhereIf(input.IsRead.HasValue, a => a.IsRead == input.IsRead)
.WhereIf(!input.IsListRequest && !input.Channels.IsNullOrEmpty() && input.Channels!.Contains(NotificationChannels.UiToast), a => a.CreationTime >= now);
return query;
}
protected override async Task> MapToGetListOutputDtosAsync(List entities)
{
var dtos = new List();
var userIds = entities.Select(a => a.CreatorId).Distinct().ToArray();
var query = await repositoryUser.GetQueryableAsync();
var users = await query.AsNoTracking().Where(a => userIds.Contains(a.Id)).Select(a => new { a.Id, Fullname = $"{a.Name} {a.Surname}".Trim(), a.TenantId }).ToDictionaryAsync(x => x.Id, x => x);
foreach (var entity in entities)
{
var dto = await MapToGetListOutputDtoAsync(entity);
if (entity.CreatorId.HasValue && users.TryGetValue(entity.CreatorId.Value, out var user))
{
dto.CreatorFullname = user.Fullname;
dto.TenantId = user.TenantId;
}
dtos.Add(dto);
}
return dtos;
}
///
/// Bir kanaldaki tum kayitlari okundu/okunmadi yapar. Kullaniciya henuz iletilmemis kayit
/// okunamaz; isaretleme onlari atlar ve gonderim gerceklestiginde tekrar okunabilir olurlar.
///
public async Task UpdateReadAllAsync(string notificationChannel, bool isRead)
{
var query = await repository.GetQueryableAsync();
var readTime = isRead ? Clock.Now : (DateTime?)null;
var affectedRows = await query
.Where(a => a.UserId == CurrentUser.Id && a.NotificationChannel == notificationChannel && a.IsRead == !isRead)
.Where(a => !isRead || a.IsSent)
.ExecuteUpdateAsync(b => b
.SetProperty(u => u.IsRead, isRead)
.SetProperty(u => u.ReadTime, readTime)
);
return affectedRows;
}
/// Secili kayitlari okundu/okunmadi yapar; kural ile aynidir.
public async Task UpdateReadManyAsync(List notificationIds, bool isRead)
{
if (notificationIds.Count == 0)
{
return 0;
}
var query = await repository.GetQueryableAsync();
var readTime = isRead ? Clock.Now : (DateTime?)null;
return await query
.Where(a => a.UserId == CurrentUser.Id && notificationIds.Contains(a.Id) && a.IsRead != isRead)
.Where(a => !isRead || a.IsSent)
.ExecuteUpdateAsync(setters => setters
.SetProperty(a => a.IsRead, isRead)
.SetProperty(a => a.ReadTime, readTime));
}
///
/// Tarayici kanallarinda (toast, masaustu) gosterim isaretidir; gosterilen kayit iletilmis
/// sayilir. Diger kanallarin gonderimi NotificationWorker'a aittir.
///
public async Task UpdateSentManyAsync(List notificationIds, bool isSent)
{
if (notificationIds.Count == 0)
{
return 0;
}
var query = await repository.GetQueryableAsync();
return await query
.Where(a => a.UserId == CurrentUser.Id && notificationIds.Contains(a.Id) && a.IsSent != isSent)
.Where(a => NotificationChannels.BrowserChannels.Contains(a.NotificationChannel))
.ExecuteUpdateAsync(setters => setters.SetProperty(a => a.IsSent, isSent));
}
[RemoteService(false)]
public override Task GetAsync(Guid id) => throw new NotImplementedException();
[RemoteService(false)]
protected override Task GetEntityByIdAsync(Guid id) => throw new NotImplementedException();
}