using LanguageExt.Common; using ParticipantGroupModule.DTOs; namespace ParticipantGroupModule.Services; public class ParticipantGroupFilterService : IParticipantGroupFilterService { private readonly CommonContext _commonContext; private readonly IUserAccessControlService _userAccessControlService; private readonly ILoggedInUserService _loggedInUserService; public ParticipantGroupFilterService( CommonContext commonContext, IUserAccessControlService userAccessControlService, ILoggedInUserService loggedInUserService) { _commonContext = commonContext; _userAccessControlService = userAccessControlService; _loggedInUserService = loggedInUserService; } private bool GroupFilterHasAnyValue(object model) { if (model == null) return false; var properties = model.GetType().GetProperties(); foreach (var property in properties) { var value = property.GetValue(model); if (value != null && property.PropertyType == typeof(string) && !string.IsNullOrWhiteSpace((string)value)) { return true; } } return false; } public object GetFilteredParticipantGroups(ParticipantGroupFilterDto participantGroupFilterDto) { var hasData = GroupFilterHasAnyValue(participantGroupFilterDto); var participantGroups = _commonContext.ParticipantGroups.AsQueryable(); if (string.IsNullOrEmpty(participantGroupFilterDto.CountryId)) { participantGroups = FilterByCountryAccess(participantGroups); } if (string.IsNullOrEmpty(participantGroupFilterDto.ProjectId)) { participantGroups = FilterByProjectAccess(participantGroups); } if (string.IsNullOrEmpty(participantGroupFilterDto.CatchmentId)) { participantGroups = FilterByVillageAccess(participantGroups); } participantGroups = participantGroups.Where(participantGroup => (string.IsNullOrEmpty(participantGroupFilterDto.CountryId) || participantGroup.CountryId == participantGroupFilterDto.CountryId) && (string.IsNullOrEmpty(participantGroupFilterDto.ProjectId) || participantGroup.ProjectId == participantGroupFilterDto.ProjectId) && (string.IsNullOrEmpty(participantGroupFilterDto.CatchmentId) || participantGroup.CatchmentId == participantGroupFilterDto.CatchmentId) && (string.IsNullOrEmpty(participantGroupFilterDto.ServicePointId) || participantGroup.ServicePointId == participantGroupFilterDto.ServicePointId) && (string.IsNullOrEmpty(participantGroupFilterDto.GroupTypeId) || participantGroup.ParticipantGroupTypeId == participantGroupFilterDto.GroupTypeId) ); var totalParticipantGroups = GetFinalParticipantGroups(participantGroups); if (!hasData) { return new { ParticipantGroups = totalParticipantGroups.Take(200).AsEnumerable(), totalGroups = totalParticipantGroups.Count() }; } return new { ParticipantGroups = totalParticipantGroups.AsEnumerable(), totalGroups = totalParticipantGroups.Count() }; } private IQueryable FilterByCountryAccess(IQueryable participantGroups) { if (_loggedInUserService.IsSystemAdmin()) { // System admin can get all participant groups. Hence, don't need to check accessed countries. return participantGroups; } var permittedCountryIds = _userAccessControlService.GetAllCountry() .Select(x => x.Id) .Distinct(); return participantGroups.Join( permittedCountryIds, p => p.CountryId, countryId => countryId, (p, c) => p); } private IQueryable FilterByProjectAccess(IQueryable participantGroups) { if (_loggedInUserService.IsSystemAdmin()) { // System admin can get all participant groups. Hence, don't need to check accessed projects. return participantGroups; } var permittedProjectIds = _userAccessControlService.GetAllProject() .Select(x => x.Id) .Distinct(); return participantGroups.Join( permittedProjectIds, participantGroup => participantGroup.ProjectId, projectId => projectId, (participantGroup, projectId) => participantGroup); } private IQueryable FilterByVillageAccess(IQueryable participantGroups) { if (_loggedInUserService.IsSystemAdmin()) { // System admin can get all participant groups. Hence, don't need to check accessed villages. return participantGroups; } var permittedVillageIds = _userAccessControlService.GetPermittedVillageIdsAsQueryable(); return participantGroups. Where(x => permittedVillageIds.Contains(x.CatchmentId!)); } private IQueryable<object> GetFinalParticipantGroups(IQueryable participantGroups) { return (from pg in participantGroups join b in _commonContext.BranchOfficeVillageMappings on new { pg.CatchmentId, pg.ProjectId } equals new { b.CatchmentId, b.ProjectId } into branchOffices from branchOffice in branchOffices.DefaultIfEmpty() join pgm in _commonContext.ParticipantGroupMembers on pg.Id equals pgm.GroupId into pgMembers group pg by new { pg.Id, pg.Name, pg.ParticipantGroupTypeId, pg.StakeholderTypeId, pg.CatchmentId, pg.ServicePointId, pg.CatchmentIdsForMemberSelection, pg.CountryId, pg.ProjectId, pg.FiscalYearId, branchOffice.BranchOfficeId, NumberOfParticipant = pgMembers.Count() } into pgGrouped select new { pgGrouped.Key.Id, pgGrouped.Key.Name, pgGrouped.Key.ParticipantGroupTypeId, pgGrouped.Key.StakeholderTypeId, pgGrouped.Key.CatchmentId, pgGrouped.Key.ServicePointId, pgGrouped.Key.CatchmentIdsForMemberSelection, pgGrouped.Key.CountryId, pgGrouped.Key.ProjectId, pgGrouped.Key.FiscalYearId, pgGrouped.Key.BranchOfficeId, pgGrouped.Key.NumberOfParticipant }); } }