using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using ClosedXML; using Kurs.Platform.BlobStoring; using Kurs.Platform.Entities; using Kurs.Platform.FileManagement; using Kurs.Platform.Intranet; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Volo.Abp.Domain.Repositories; using Volo.Abp.MultiTenancy; namespace Kurs.Platform.Public; [Authorize] public class IntranetAppService : PlatformAppService, IIntranetAppService { private readonly ICurrentTenant _currentTenant; private readonly BlobManager _blobContainer; private readonly IConfiguration _configuration; private readonly IRepository _eventRepository; private readonly IRepository _employeeRepository; private readonly IRepository _visitorRepository; private readonly IRepository _reservationRepository; private readonly IRepository _trainingRepository; private readonly IRepository _expenseRepository; private readonly IRepository _announcementRepository; private readonly IRepository _departmentRepository; private readonly IRepository _shuttleRouteRepository; private readonly IRepository _mealRepository; public IntranetAppService( ICurrentTenant currentTenant, BlobManager blobContainer, IConfiguration configuration, IRepository eventRepository, IRepository employeeRepository, IRepository visitorRepository, IRepository reservationRepository, IRepository trainingRepository, IRepository expenseRepository, IRepository announcementRepository, IRepository departmentRepository, IRepository shuttleRouteRepository, IRepository mealRepository ) { _currentTenant = currentTenant; _blobContainer = blobContainer; _configuration = configuration; _eventRepository = eventRepository; _employeeRepository = employeeRepository; _visitorRepository = visitorRepository; _reservationRepository = reservationRepository; _trainingRepository = trainingRepository; _expenseRepository = expenseRepository; _announcementRepository = announcementRepository; _departmentRepository = departmentRepository; _shuttleRouteRepository = shuttleRouteRepository; _mealRepository = mealRepository; } public async Task GetIntranetDashboardAsync() { return new IntranetDashboardDto { Events = await GetUpcomingEventsAsync(), Birthdays = await GetBirthdaysAsync(), Visitors = await GetVisitorsAsync(), Reservations = await GetReservationsAsync(), Trainings = await GetTrainingsAsync(), Expenses = await GetExpensesAsync(), Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet), Announcements = await GetAnnouncementsAsync(), ShuttleRoutes = await GetShuttleRoutesAsync(), Meals = await GetMealsAsync() }; } private async Task> GetMealsAsync() { // Bu haftanın başlangıç ve bitiş tarihlerini hesapla var today = DateTime.Now.Date; var dayOfWeek = (int)today.DayOfWeek; // Pazartesi'yi haftanın başı olarak kabul ediyoruz (ISO 8601) var weekStart = today.AddDays(-(dayOfWeek == 0 ? 6 : dayOfWeek - 1)); var weekEnd = weekStart.AddDays(6); // Sadece bu haftanın yemeklerini getir var meals = await _mealRepository.GetListAsync(m => m.Date >= weekStart && m.Date <= weekEnd); var mealDtos = new List(); foreach (var meal in meals) { var dto = ObjectMapper.Map(meal); if (!string.IsNullOrEmpty(meal.Materials)) { dto.Materials = meal.Materials .Split('|', StringSplitOptions.RemoveEmptyEntries) .Select(r => r.Trim()) .ToArray(); } else { dto.Materials = []; } mealDtos.Add(dto); } return mealDtos; } private async Task> GetShuttleRoutesAsync() { var shuttleRoutes = await _shuttleRouteRepository.GetListAsync(); var shuttleRouteDtos = new List(); foreach (var shuttleRoute in shuttleRoutes) { var dto = ObjectMapper.Map(shuttleRoute); // Route string'ini array'e çevir (pipe ile ayrılmış) if (!string.IsNullOrEmpty(shuttleRoute.Route)) { dto.Route = shuttleRoute.Route .Split('|', StringSplitOptions.RemoveEmptyEntries) .Select(r => r.Trim()) .ToArray(); } else { dto.Route = []; } shuttleRouteDtos.Add(dto); } return shuttleRouteDtos; } private async Task> GetAnnouncementsAsync() { var announcements = await _announcementRepository .WithDetailsAsync(e => e.Employee) .ContinueWith(t => t.Result.ToList()); var announcementDtos = new List(); // Tüm departmanları bir kez çek (performans için) var allDepartments = await _departmentRepository.GetListAsync(); foreach (var announcement in announcements) { var dto = ObjectMapper.Map(announcement); // Departments string'ini array'e çevir (pipe ile ayrılmış ID'ler) if (!string.IsNullOrEmpty(announcement.Departments)) { var departmentIds = announcement.Departments .Split('|', StringSplitOptions.RemoveEmptyEntries) .Select(d => d.Trim()) .ToArray(); // ID'leri Department Name'lere çevir var departmentNames = new List(); foreach (var deptId in departmentIds) { if (Guid.TryParse(deptId, out var guid)) { var department = allDepartments.FirstOrDefault(d => d.Id == guid); if (department != null) { departmentNames.Add(department.Name); } } } dto.Departments = departmentNames.ToArray(); } else { dto.Departments = []; } announcementDtos.Add(dto); } return announcementDtos; } private async Task GetExpensesAsync() { var queryable = await _expenseRepository.GetQueryableAsync(); var today = DateTime.Today; var oneMonthAgo = today.AddMonths(-1); // Son 1 ay içerisindeki kayıtlar var lastMonthExpenses = queryable .Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today); // Son 1 aydaki toplam talep miktarı var totalRequested = lastMonthExpenses.Sum(a => a.Amount); // Son 1 aydaki onaylanan harcamaların toplamı var totalApproved = lastMonthExpenses .Where(a => a.Status == "approved") .Sum(a => a.Amount); // Son 5 kayıt var last5Expenses = queryable .OrderByDescending(a => a.RequestDate) .Take(5) .ToList(); // Map işlemleri var last5Dtos = ObjectMapper.Map, List>(last5Expenses); // Dönüş DTO'su return new ExpensesDto { TotalRequested = totalRequested, TotalApproved = totalApproved, Last5Expenses = last5Dtos }; } private async Task> GetTrainingsAsync() { var trainings = await _trainingRepository.GetListAsync(a => a.StartDate >= DateTime.Today); return ObjectMapper.Map, List>(trainings); } private async Task> GetReservationsAsync() { var reservations = await _reservationRepository.GetListAsync(a => a.StartDate >= DateTime.Today); return ObjectMapper.Map, List>(reservations); } private async Task> GetVisitorsAsync() { var visitors = await _visitorRepository.GetListAsync(a => a.VisitDate >= DateTime.Today); return ObjectMapper.Map, List>(visitors); } private async Task> GetBirthdaysAsync() { var today = DateTime.Now; var employees = await _employeeRepository .WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department) .ContinueWith(t => t.Result .Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month) .ToList()); return ObjectMapper.Map, List>(employees); } private async Task> GetUpcomingEventsAsync() { var events = await _eventRepository .WithDetailsAsync(e => e.Category, e => e.Type, e => e.Category, e => e.Photos, e => e.Comments) .ContinueWith(t => t.Result.ToList().Where(e => e.isPublished).OrderByDescending(e => e.CreationTime)); var result = new List(); foreach (var evt in events) { var employee = await _employeeRepository .WithDetailsAsync(e => e.JobPosition) .ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == evt.EmployeeId)); if (employee != null) { var calendarEvent = new EventDto { Id = evt.Id.ToString(), Name = evt.Name, Description = evt.Description, TypeName = evt.Type?.Name, CategoryName = evt.Category?.Name, Date = evt.Date, Place = evt.Place, Organizer = new EventOrganizerDto { Id = employee.Id, Name = employee.FullName, Position = employee.JobPosition.Name, Avatar = employee.Avatar }, Participants = evt.ParticipantsCount, Photos = [], Comments = [], Likes = evt.Likes, IsPublished = evt.isPublished }; // Comment'lerin author bilgilerini doldur if (evt.Comments != null && evt.Comments.Any()) { foreach (var comment in evt.Comments) { var commentAuthor = await _employeeRepository .WithDetailsAsync(e => e.JobPosition) .ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == comment.EmployeeId)); if (commentAuthor != null) { calendarEvent.Comments.Add(new EventCommentDto { Id = comment.Id.ToString(), Author = new EventOrganizerDto { Id = commentAuthor.Id, Name = commentAuthor.FullName, Position = commentAuthor.JobPosition.Name, Avatar = commentAuthor.Avatar }, Content = comment.Content, CreationTime = comment.CreationTime, Likes = comment.Likes }); } } } result.Add(calendarEvent); } } return result; } 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 }); } 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" }; } }