using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Sozsoft.Platform.Entities; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; namespace Sozsoft.Platform.VideoRooms; [Authorize] public class VideoroomAppService : PlatformAppService, IVideoroomAppService { private readonly IRepository _classSessionRepository; private readonly IRepository _participantRepository; private readonly IRepository _attendanceRepository; private readonly IRepository _chatRepository; public VideoroomAppService( IRepository classSessionRepository, IRepository participantRepository, IRepository attendanceRepository, IRepository chatRepository) { _classSessionRepository = classSessionRepository; _participantRepository = participantRepository; _attendanceRepository = attendanceRepository; _chatRepository = chatRepository; } public async Task GetAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); return ObjectMapper.Map(classSession); } public async Task> GetListAsync(VideoroomFilterInputDto input) { var query = await _classSessionRepository.GetQueryableAsync(); if (!string.IsNullOrWhiteSpace(input.Search)) { query = query.Where(x => x.Name.Contains(input.Search) || x.Description.Contains(input.Search) || x.Subject.Contains(input.Search) || x.TeacherName.Contains(input.Search) ); } if (!string.IsNullOrWhiteSpace(input.Status)) { switch (input.Status) { case "Active": query = query.Where(x => x.ActualStartTime == null && x.ActualEndTime == null); break; case "Open": query = query.Where(x => x.ActualStartTime != null && x.ActualEndTime == null); break; case "Passive": query = query.Where(x => x.ActualEndTime != null); break; } } var totalCount = query.Count(); var items = query .OrderBy(x => x.ScheduledStartTime) .Skip(input.SkipCount) .Take(input.MaxResultCount) .ToList(); return new PagedResultDto( totalCount, ObjectMapper.Map, List>(items) ); } public async Task CreateAsync(VideoroomDto input) { var classSession = new Videoroom { Name = input.Name, Description = input.Description, Subject = input.Subject, TeacherId = CurrentUser.Id, TeacherName = CurrentUser.Name, ScheduledStartTime = input.ScheduledStartTime, ScheduledEndTime = input.ScheduledStartTime.AddMinutes(input.Duration), Duration = input.Duration, MaxParticipants = input.MaxParticipants, SettingsJson = JsonSerializer.Serialize(input.SettingsDto) }; await _classSessionRepository.InsertAsync(classSession); return ObjectMapper.Map(classSession); } public async Task UpdateAsync(Guid id, VideoroomDto input) { var classSession = await _classSessionRepository.GetAsync(id); if (classSession.TeacherId != CurrentUser.Id) { throw new UnauthorizedAccessException("Only the teacher can update this class"); } classSession.Name = input.Name; classSession.Description = input.Description; classSession.Subject = input.Subject; classSession.TeacherId = input.TeacherId; classSession.TeacherName = input.TeacherName; classSession.ScheduledStartTime = input.ScheduledStartTime; classSession.ScheduledEndTime = input.ScheduledStartTime.AddMinutes(input.Duration); classSession.Duration = input.Duration; classSession.MaxParticipants = input.MaxParticipants; classSession.SettingsJson = JsonSerializer.Serialize(input.SettingsDto); await _classSessionRepository.UpdateAsync(classSession); return ObjectMapper.Map(classSession); } public async Task DeleteAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); if (classSession.TeacherId != CurrentUser.Id) { throw new UnauthorizedAccessException("Only the teacher can delete this class"); } await _classSessionRepository.DeleteAsync(id); } [HttpPut] public async Task StartClassAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); if (classSession.TeacherId != CurrentUser.Id) { throw new UnauthorizedAccessException("Only the teacher can start this class"); } classSession.ActualStartTime = DateTime.Now; await _classSessionRepository.UpdateAsync(classSession); return ObjectMapper.Map(classSession); } [HttpPut] public async Task EndClassAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); if (classSession.TeacherId != CurrentUser.Id) { throw new UnauthorizedAccessException("Only the teacher can end this class"); } classSession.ActualEndTime = DateTime.Now; await _classSessionRepository.UpdateAsync(classSession); // Update attendance records var activeAttendances = await _attendanceRepository.GetListAsync( x => x.SessionId == id && x.LeaveTime == null ); foreach (var attendance in activeAttendances) { attendance.LeaveTime = DateTime.Now; attendance.CalculateDuration(); await _attendanceRepository.UpdateAsync(attendance); } } public async Task JoinClassAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); if (classSession == null) { throw new InvalidOperationException("Class not found"); } var videoroomSettings = string.IsNullOrWhiteSpace(classSession.SettingsJson) ? new VideoroomSettingsDto() // default ayarlar : JsonSerializer.Deserialize(classSession.SettingsJson); if (classSession.ParticipantCount >= classSession.MaxParticipants) { throw new InvalidOperationException("Class is full"); } // Check if user is already in the class var existingParticipant = await _participantRepository.FirstOrDefaultAsync( x => x.SessionId == id && x.UserId == CurrentUser.Id ); if (existingParticipant == null) { // Add participant var participant = new VideoroomParticipant( GuidGenerator.Create(), id, CurrentUser.Id, CurrentUser.Name, false, // isTeacher videoroomSettings?.DefaultMicrophoneState == "muted", videoroomSettings?.DefaultCameraState == "off", false, // HandRaised false, // isKicked true // isActive ); await _participantRepository.InsertAsync(participant); // Create attendance record var attendance = new VideoroomAttandance( GuidGenerator.Create(), id, CurrentUser.Id, CurrentUser.Name, DateTime.Now ); await _attendanceRepository.InsertAsync(attendance); // Update participant count classSession.ParticipantCount++; await _classSessionRepository.UpdateAsync(classSession); } return ObjectMapper.Map(classSession); } public async Task LeaveClassAsync(Guid id) { var participant = await _participantRepository.FirstOrDefaultAsync( x => x.SessionId == id && x.UserId == CurrentUser.Id ); if (participant != null) { await _participantRepository.DeleteAsync(participant); // Update attendance record var attendance = await _attendanceRepository.FirstOrDefaultAsync( x => x.SessionId == id && x.StudentId == CurrentUser.Id && x.LeaveTime == null ); if (attendance != null) { attendance.LeaveTime = DateTime.UtcNow; attendance.CalculateDuration(); await _attendanceRepository.UpdateAsync(attendance); } // Update participant count var classSession = await _classSessionRepository.GetAsync(id); classSession.ParticipantCount = Math.Max(0, classSession.ParticipantCount - 1); await _classSessionRepository.UpdateAsync(classSession); } } public async Task> GetAttendanceAsync(Guid sessionId) { var attendanceRecords = await _attendanceRepository.GetListAsync( x => x.SessionId == sessionId ); return ObjectMapper.Map, List>(attendanceRecords); } public async Task> GetParticipantAsync(Guid sessionId) { var participantRecords = await _participantRepository.GetListAsync( x => x.SessionId == sessionId ); return ObjectMapper.Map, List>(participantRecords); } public async Task> GetChatAsync(Guid sessionId) { var chatRecords = await _chatRepository.GetListAsync( x => x.SessionId == sessionId ); return ObjectMapper.Map, List>(chatRecords); } }