using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading.Tasks; using Sozsoft.Languages.Entities; using Sozsoft.Platform.Entities; using Sozsoft.Platform.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; using Volo.Abp.PermissionManagement; using Volo.Abp.TenantManagement; using static Sozsoft.Platform.Data.Seeds.SeedConsts; using Sozsoft.Languages; namespace Sozsoft.Platform.Menus; [Authorize] public class MenuAppService : CrudAppService< Menu, MenuDto, Guid, PagedAndSortedResultRequestDto> { private readonly IRepository _menuRepository; private readonly IRepository _repositoryKey; private readonly IRepository _repositoryText; private readonly ITenantRepository _tenantRepository; private readonly IPermissionDefinitionRecordRepository _permissionRepository; public MenuAppService( IRepository menuRepository, IRepository languageKeyRepository, IRepository languageTextRepository, ITenantRepository tenantRepository, IPermissionDefinitionRecordRepository permissionRepository ) : base(menuRepository) { _menuRepository = menuRepository; _repositoryKey = languageKeyRepository; _repositoryText = languageTextRepository; _tenantRepository = tenantRepository; _permissionRepository = permissionRepository; CreatePolicyName = $"{AppCodes.Menus.Menu}.Create"; UpdatePolicyName = $"{AppCodes.Menus.Menu}.Update"; DeletePolicyName = $"{AppCodes.Menus.Menu}.Delete"; } public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) { await CheckGetListPolicyAsync(); var query = await CreateFilteredQueryAsync(input); query = query.Where(a => !a.IsDisabled); //Tenant üzerinden MenuGrup bilgisi alınıp sadece o menüler listelenecek if (CurrentTenant.IsAvailable) { var tenant = await _tenantRepository.FindAsync(CurrentTenant.Id.Value); if (tenant != null) { var tenantMenuGroup = tenant.GetMenuGroup(); if (!tenantMenuGroup.IsNullOrWhiteSpace()) { var permissionRecords = await _permissionRepository.GetListAsync(); var allowedPermissionNames = permissionRecords .Where(p => p.GetMenuGroup().Contains(tenantMenuGroup)) .Select(p => p.Name) .Distinct() .ToList(); query = query.Where(menu => string.IsNullOrEmpty(menu.RequiredPermissionName) || allowedPermissionNames.Contains(menu.RequiredPermissionName)); } } } var totalCount = await AsyncExecuter.CountAsync(query); var entities = new List(); var entityDtos = new List(); if (totalCount > 0) { query = ApplySorting(query, input); query = ApplyPaging(query, input); var items = await AsyncExecuter.ToListAsync(query); // Tüm unique permission'ları topla var uniquePermissions = items .Where(x => !string.IsNullOrWhiteSpace(x.RequiredPermissionName)) .Select(x => x.RequiredPermissionName) .Distinct() .ToList(); // Tüm permission'ları bir kerede kontrol et (N+1 query problemini önler) var grantedPermissions = new HashSet(); foreach (var permission in uniquePermissions) { try { if (await AuthorizationService.IsGrantedAsync(permission)) { grantedPermissions.Add(permission); } } catch (Exception ex) { Logger.LogError(ex, $"Permission error for {permission}: {ex.Message}"); } } // Sadece yetkili menüleri filtrele entities = items .Where(item => string.IsNullOrWhiteSpace(item.RequiredPermissionName) || grantedPermissions.Contains(item.RequiredPermissionName)) .ToList(); entityDtos = await base.MapToGetListOutputDtosAsync(entities); } return new PagedResultDto( totalCount, entityDtos ); } public override async Task CreateAsync(MenuDto input) { await CheckCreatePolicyAsync(); var keyExists = await _repositoryKey.AnyAsync( a => a.Key == input.DisplayName && a.ResourceName == PlatformConsts.AppName); if (!keyExists) { await _repositoryKey.InsertAsync(new LanguageKey { Key = input.DisplayName, ResourceName = PlatformConsts.AppName }); } return await base.CreateAsync(input); } public override async Task UpdateAsync(Guid id, MenuDto input) { await CheckUpdatePolicyAsync(); var key = await _repositoryKey.FirstOrDefaultAsync( a => a.Key == input.DisplayName && a.ResourceName == PlatformConsts.AppName); if (key is null) { // Yeni Key'i olustur await _repositoryKey.InsertAsync(new LanguageKey { Key = input.DisplayName, ResourceName = PlatformConsts.AppName }); } return await base.UpdateAsync(id, input); } public async Task> UpdateAllAsync(List inputs) { await CheckUpdatePolicyAsync(); if (!inputs.Any()) return new List(); // Id kontrolü if (inputs.Any(x => x.Id == Guid.Empty)) { throw new ArgumentException("MenuDto içinde geçerli bir Id bulunmalıdır."); } // Tüm DisplayName'leri topla var displayNames = inputs.Select(x => x.DisplayName).Distinct().ToList(); // Mevcut key'leri tek sorguda getir var existingKeys = await AsyncExecuter.ToListAsync( (await _repositoryKey.GetQueryableAsync()) .Where(a => displayNames.Contains(a.Key) && a.ResourceName == PlatformConsts.AppName)); var existingKeyNames = existingKeys.Select(x => x.Key).ToHashSet(); // Eksik key'leri toplu ekle var newKeys = displayNames .Where(name => !existingKeyNames.Contains(name)) .Select(name => new LanguageKey { Key = name, ResourceName = PlatformConsts.AppName }) .ToList(); if (newKeys.Any()) { await _repositoryKey.InsertManyAsync(newKeys, autoSave: true); } // Menüleri güncelle var result = new List(); foreach (var input in inputs) { var updated = await base.UpdateAsync(input.Id, input); result.Add(updated); } return result; } public override async Task DeleteAsync(Guid id) { await CheckDeletePolicyAsync(); var menu = await _menuRepository.GetAsync(id); if (menu != null) { await _repositoryKey.DeleteAsync( a => a.Key == menu.DisplayName && a.ResourceName == PlatformConsts.AppName); } await base.DeleteAsync(id); } public async Task> GetListMainMenuAsync() { await CheckGetPolicyAsync(); var query = await _menuRepository.GetQueryableAsync(); query = query.Where(a => !a.IsDisabled && a.ShortName != null); var entities = await AsyncExecuter.ToListAsync(query); var entityDtos = await MapToGetListOutputDtosAsync(entities); return entityDtos; } public async Task CreateWithLanguageKeyTextAsync(MenuDto input) { await CheckCreatePolicyAsync(); //Dil Key oluşturuluyor. var keyExists = await _repositoryKey.AnyAsync( a => a.Key == input.Code && a.ResourceName == PlatformConsts.AppName); if (!keyExists) { await _repositoryKey.InsertAsync(new LanguageKey { Key = input.Code, ResourceName = PlatformConsts.AppName }, autoSave: true); } // English text oluşturuluyor veya güncelleniyor. var existingEnText = await _repositoryText.FirstOrDefaultAsync( a => a.CultureName == "en" && a.Key == input.Code && a.ResourceName == PlatformConsts.AppName); if (existingEnText != null) { existingEnText.Value = input.MenuTextEn; await _repositoryText.UpdateAsync(existingEnText); } else { await _repositoryText.InsertAsync(new LanguageText { Key = input.Code, CultureName = "en", Value = input.MenuTextEn, ResourceName = PlatformConsts.AppName }); } // Türkçe text oluşturuluyor veya güncelleniyor. var existingTrText = await _repositoryText.FirstOrDefaultAsync( a => a.CultureName == "tr" && a.Key == input.Code && a.ResourceName == PlatformConsts.AppName); if (existingTrText != null) { existingTrText.Value = input.MenuTextTr; await _repositoryText.UpdateAsync(existingTrText); } else { await _repositoryText.InsertAsync(new LanguageText { Key = input.Code, CultureName = "tr", Value = input.MenuTextTr, ResourceName = PlatformConsts.AppName }); } return await base.CreateAsync(input); } }