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(); }