using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Kurs.Platform.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; namespace Kurs.Platform.Classrooms; [Authorize] public class ClassroomAppService : PlatformAppService, IClassroomAppService { private readonly IRepository _classSessionRepository; private readonly IRepository _participantRepository; private readonly IRepository _attendanceRepository; public ClassroomAppService( IRepository classSessionRepository, IRepository participantRepository, IRepository attendanceRepository) { _classSessionRepository = classSessionRepository; _participantRepository = participantRepository; _attendanceRepository = attendanceRepository; } public async Task GetAsync(Guid id) { var classSession = await _classSessionRepository.GetAsync(id); return ObjectMapper.Map(classSession); } public async Task> GetListAsync(PagedAndSortedResultRequestDto input) { var query = await _classSessionRepository.GetQueryableAsync(); 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(ClassroomDto input) { var classSession = new Classroom( GuidGenerator.Create(), input.Name, input.Description, input.Subject, CurrentUser.Id, CurrentUser.Name, input.ScheduledStartTime, input.ScheduledStartTime.AddMinutes(input.Duration), input.Duration, input.MaxParticipants, input.SettingsJson = JsonSerializer.Serialize(input.SettingsDto) ); await _classSessionRepository.InsertAsync(classSession); return ObjectMapper.Map(classSession); } public async Task UpdateAsync(Guid id, ClassroomDto 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.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 ClassParticipant( GuidGenerator.Create(), id, CurrentUser.Id, CurrentUser.Name, CurrentUser.Email, false // isTeacher ); await _participantRepository.InsertAsync(participant); // Create attendance record var attendance = new ClassAttandance( 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 classSession = await _classSessionRepository.GetAsync(sessionId); if (classSession.TeacherId != CurrentUser.Id) { throw new UnauthorizedAccessException("Only the teacher can view attendance"); } var attendanceRecords = await _attendanceRepository.GetListAsync( x => x.SessionId == sessionId ); return ObjectMapper.Map, List>(attendanceRecords); } }