using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Sozsoft.Platform.BlobStoring; using Sozsoft.Platform.Entities; using Sozsoft.Platform.FileManagement; using Sozsoft.Platform.Identity.Dto; using Sozsoft.Platform.Extensions; using Volo.Abp.Domain.Repositories; using Volo.Abp.Identity; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; using Microsoft.AspNetCore.Mvc; namespace Sozsoft.Platform.Intranet; [Authorize] public class IntranetAppService : PlatformAppService, IIntranetAppService { private readonly ICurrentTenant _currentTenant; private readonly BlobManager _blobContainer; private readonly IConfiguration _configuration; private readonly IIdentityUserAppService _identityUserAppService; private readonly IIdentityUserRepository _identityUserRepository; private readonly IRepository _departmentRepository; private readonly IRepository _jobPositionRepository; private readonly IRepository _announcementRepository; private readonly IRepository _surveyRepository; private readonly IRepository _surveyResponseRepository; private readonly IRepository _surveyAnswerRepository; private readonly IRepository _socialPostRepository; public IntranetAppService( ICurrentTenant currentTenant, BlobManager blobContainer, IConfiguration configuration, IIdentityUserAppService identityUserAppService, IIdentityUserRepository identityUserRepository, IRepository departmentRepository, IRepository jobPositionRepository, IRepository announcementRepository, IRepository surveyRepository, IRepository surveyResponseRepository, IRepository surveyAnswerRepository, IRepository socialPostRepository ) { _currentTenant = currentTenant; _blobContainer = blobContainer; _configuration = configuration; _identityUserAppService = identityUserAppService; _identityUserRepository = identityUserRepository; _departmentRepository = departmentRepository; _jobPositionRepository = jobPositionRepository; _announcementRepository = announcementRepository; _surveyRepository = surveyRepository; _surveyResponseRepository = surveyResponseRepository; _surveyAnswerRepository = surveyAnswerRepository; _socialPostRepository = socialPostRepository; } [UnitOfWork] public async Task GetIntranetDashboardAsync() { return new IntranetDashboardDto { Birthdays = await GetBirthdaysAsync(), //1 Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet), //2 Announcements = await GetAnnouncementsAsync(), //3 Surveys = await GetSurveysAsync(), //4 SocialPosts = await GetSocialPostsAsync(), //5 }; } private async Task> GetBirthdaysAsync() { var today = DateTime.Now; var users = await _identityUserRepository.GetListAsync(); var userList = users .Where(u => { var birthDate = u.GetBirthDate(); return birthDate.HasValue && birthDate.Value.Day == today.Day && birthDate.Value.Month == today.Month; }) .ToList(); var allDepartments = await _departmentRepository.GetListAsync(); var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name); var allJobPositions = await _jobPositionRepository.GetListAsync(); var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j); var result = ObjectMapper.Map, List>(userList); for (var i = 0; i < userList.Count; i++) { var user = userList[i]; result[i].BirthDate = user.GetBirthDate(); result[i].WorkHour = user.GetWorkHour(); result[i].Nationality = user.GetNationality(); var deptId = user.GetDepartmentId(); if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName)) { result[i].DepartmentId = deptId; result[i].Departments = [ new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true } ]; } var jobPosId = user.GetJobPositionId(); if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition)) { result[i].JobPositionId = jobPosId; result[i].JobPositions = [ new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true } ]; } } return result; } private async Task> GetAnnouncementsAsync() { var announcements = await _announcementRepository.GetListAsync(); var announcementDtos = new List(); var allDepartments = await _departmentRepository.GetListAsync(); var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name); var allJobPositions = await _jobPositionRepository.GetListAsync(); var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j); foreach (var announcement in announcements) { var dto = ObjectMapper.Map(announcement); var user = await _identityUserRepository.FindAsync(announcement.UserId ?? Guid.Empty); if (user != null) { var userVm = ObjectMapper.Map(user); userVm.BirthDate = user.GetBirthDate(); userVm.WorkHour = user.GetWorkHour(); userVm.Nationality = user.GetNationality(); var deptId = user.GetDepartmentId(); if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName)) { userVm.DepartmentId = deptId; userVm.Departments = [ new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true } ]; } var jobPosId = user.GetJobPositionId(); if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition)) { userVm.JobPositionId = jobPosId; userVm.JobPositions = [ new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true } ]; } dto.User = userVm; } announcementDtos.Add(dto); } return announcementDtos; } private async Task> GetSurveysAsync() { var queryable = await _surveyRepository.GetQueryableAsync(); var surveys = await AsyncExecuter.ToListAsync( queryable .AsNoTracking() .Where(s => s.Status == "active") .Include(s => s.Questions) .ThenInclude(q => q.Options) ); var dtos = ObjectMapper.Map, List>(surveys); // Tüm anketler için mevcut kullanıcının cevabını çek (anonim dahil — CreatorId ile) if (CurrentUser.IsAuthenticated) { var allSurveyIds = surveys.Select(s => s.Id).ToList(); if (allSurveyIds.Any()) { var rq = await _surveyResponseRepository.GetQueryableAsync(); var myResponses = await AsyncExecuter.ToListAsync( rq.AsNoTracking() .Where(r => allSurveyIds.Contains(r.SurveyId) && (r.UserId == CurrentUser.Id || r.CreatorId == CurrentUser.Id)) .Include(r => r.Answers) ); var responseMap = myResponses.ToDictionary(r => r.SurveyId); for (var i = 0; i < surveys.Count; i++) { if (responseMap.TryGetValue(surveys[i].Id, out var myResponse)) dtos[i].MyResponse = ObjectMapper.Map(myResponse); } } } return dtos; } private async Task> GetSocialPostsAsync() { var queryable = await _socialPostRepository .WithDetailsAsync(e => e.Location, e => e.Media, e => e.Comments, e => e.Likes); var socialPosts = await AsyncExecuter.ToListAsync(queryable); var dtos = ObjectMapper.Map, List>(socialPosts); // Collect all unique user IDs to resolve in a single query var userIds = dtos .Select(p => p.UserId) .Union(dtos.SelectMany(p => p.Comments.Select(c => c.UserId))) .Union(dtos.SelectMany(p => p.Likes.Select(l => l.UserId))) .Where(id => id.HasValue) .Select(id => id!.Value) .Distinct() .ToList(); if (userIds.Count > 0) { var allDepartments = await _departmentRepository.GetListAsync(); var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name); var allJobPositions = await _jobPositionRepository.GetListAsync(); var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j); var users = await _identityUserRepository.GetListAsync(); var userMap = users .Where(u => userIds.Contains(u.Id)) .ToDictionary(u => u.Id, u => { var vm = ObjectMapper.Map(u); vm.BirthDate = u.GetBirthDate(); vm.WorkHour = u.GetWorkHour(); vm.Nationality = u.GetNationality(); var deptId = u.GetDepartmentId(); if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName)) { vm.DepartmentId = deptId; vm.Departments = [ new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true } ]; } var jobPosId = u.GetJobPositionId(); if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition)) { vm.JobPositionId = jobPosId; vm.JobPositions = [ new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true } ]; } return vm; }); foreach (var dto in dtos) { if (dto.UserId.HasValue && userMap.TryGetValue(dto.UserId.Value, out var postUser)) dto.User = postUser; foreach (var comment in dto.Comments) if (comment.UserId.HasValue && userMap.TryGetValue(comment.UserId.Value, out var commentUser)) comment.User = commentUser; foreach (var like in dto.Likes) if (like.UserId.HasValue && userMap.TryGetValue(like.UserId.Value, out var likeUser)) like.User = likeUser; } } return dtos; } public async Task> GetIntranetDocumentsAsync(string folderPath) { var items = new List(); var cdnBasePath = _configuration["App:CdnPath"]; if (string.IsNullOrEmpty(cdnBasePath)) { Logger.LogWarning("CDN path is not configured"); return items; } var tenantId = _currentTenant.Id?.ToString() ?? "host"; var fullPath = Path.Combine(cdnBasePath, tenantId); if (!string.IsNullOrEmpty(folderPath)) { fullPath = Path.Combine(fullPath, folderPath); } if (!Directory.Exists(fullPath)) { Logger.LogWarning($"Directory not found: {fullPath}"); return items; } var files = Directory.GetFiles(fullPath); foreach (var file in files) { var fileInfo = new FileInfo(file); var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}"; items.Add(new FileItemDto { Id = Guid.NewGuid().ToString(), Name = fileInfo.Name, Type = "file", Size = fileInfo.Length, Extension = fileInfo.Extension, MimeType = GetMimeType(fileInfo.Extension), CreatedAt = fileInfo.CreationTime, ModifiedAt = fileInfo.LastWriteTime, Path = relativePath, ParentId = string.Empty, IsReadOnly = false, ChildCount = 0, TenantId = _currentTenant.Id?.ToString() }); } return items.OrderBy(x => x.Name).ToList(); } private string GetMimeType(string extension) { return extension.ToLowerInvariant() switch { ".pdf" => "application/pdf", ".doc" => "application/msword", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xls" => "application/vnd.ms-excel", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".ppt" => "application/vnd.ms-powerpoint", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".jpg" or ".jpeg" => "image/jpeg", ".png" => "image/png", ".gif" => "image/gif", ".txt" => "text/plain", ".zip" => "application/zip", ".rar" => "application/x-rar-compressed", _ => "application/octet-stream" }; } [HttpPost] public async Task UpdateSurveyResponseAsync(SubmitSurveyInput input) { var survey = await _surveyRepository.GetAsync(input.SurveyId); SurveyResponse? response = null; if (CurrentUser.IsAuthenticated) { var responseQueryable = await _surveyResponseRepository.GetQueryableAsync(); response = await AsyncExecuter.FirstOrDefaultAsync( responseQueryable.Where(r => r.SurveyId == input.SurveyId && (r.UserId == CurrentUser.Id || r.CreatorId == CurrentUser.Id)) ); } if (response != null) { var answerQueryable = await _surveyAnswerRepository.GetQueryableAsync(); var existingAnswers = await AsyncExecuter.ToListAsync( answerQueryable.Where(a => a.ResponseId == response.Id) ); var existingAnswerMap = existingAnswers.ToDictionary(x => x.QuestionId); foreach (var inputAnswer in input.Answers) { if (existingAnswerMap.TryGetValue(inputAnswer.QuestionId, out var existingAnswer)) { existingAnswer.Value = inputAnswer.Value ?? string.Empty; existingAnswer.QuestionType = inputAnswer.QuestionType; await _surveyAnswerRepository.UpdateAsync(existingAnswer); } else { await _surveyAnswerRepository.InsertAsync(new SurveyAnswer(Guid.NewGuid()) { ResponseId = response.Id, QuestionId = inputAnswer.QuestionId, QuestionType = inputAnswer.QuestionType, Value = inputAnswer.Value ?? string.Empty }); } } response.SubmissionTime = Clock.Now; await _surveyResponseRepository.UpdateAsync(response); return; } var newResponse = new SurveyResponse(Guid.NewGuid()) { SurveyId = input.SurveyId, UserId = survey.IsAnonymous ? null : CurrentUser.Id, SubmissionTime = Clock.Now, Answers = input.Answers.Select(a => new SurveyAnswer(Guid.NewGuid()) { QuestionId = a.QuestionId, QuestionType = a.QuestionType, Value = a.Value ?? string.Empty }).ToList() }; await _surveyResponseRepository.InsertAsync(newResponse); survey.Responses++; await _surveyRepository.UpdateAsync(survey); } }