From 4320469e883005be41464439d84668f4e79a7294 Mon Sep 17 00:00:00 2001 From: VoOneChek Date: Tue, 27 May 2025 20:56:58 +0400 Subject: [PATCH] =?UTF-8?q?CRUD=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=84=D0=B0=D0=BA=D1=83?= =?UTF-8?q?=D0=BB=D1=8C=D1=82=D0=B5=D1=82=D0=B0,=20=D0=BD=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F,=20=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D1=86=D0=B8=D0=BF=D0=BB=D0=B8=D0=BD=D1=8B,=20?= =?UTF-8?q?=D1=81=D1=82=D1=83=D0=B4=D0=B5=D0=BD=D1=82=D0=B0,=20=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=BF=D0=BF=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DTOs/Direction/DirectionCreateDto.cs | 16 +++ .../DTOs/Direction/DirectionDetailDto.cs | 19 +++ .../DTOs/Direction/DirectionTableDto.cs | 15 +++ .../DTOs/Discipline/DisciplineCreateDto.cs | 15 +++ .../DTOs/Discipline/DisciplineDetailDto.cs | 17 +++ .../DTOs/Discipline/DisciplineTableDto.cs | 15 +++ .../DTOs/Faculty/FacultyCreateDto.cs | 14 +++ .../DTOs/Faculty/FacultyReadDto.cs | 16 +++ .../DTOs/Group/GroupCreateDto.cs | 15 +++ .../DTOs/Group/GroupDetailDto.cs | 17 +++ .../DTOs/Group/GroupTableDto.cs | 14 +++ .../DTOs/Student/GradeInStudentDto.cs | 21 ---- .../DTOs/Student/StudentCreateDto.cs | 1 - .../DTOs/Student/StudentReadDto.cs | 4 - .../DTOs/Student/StudentTableDto.cs | 15 --- .../Interfaces/IBaseRepository.cs | 6 +- .../Services/DirectionService.cs | 114 ++++++++++++++++++ .../Services/DisciplineService.cs | 95 +++++++++++++++ .../Services/FacultyService.cs | 107 ++++++++++++++++ .../Services/GroupService.cs | 98 +++++++++++++++ .../Services/StudentService.cs | 27 ++--- GradeBookServer.Domain/Entities/Direction.cs | 5 +- GradeBookServer.Domain/Entities/Discipline.cs | 6 +- GradeBookServer.Domain/Entities/Faculty.cs | 5 +- GradeBookServer.Domain/Entities/Grade.cs | 3 +- GradeBookServer.Domain/Entities/Group.cs | 5 +- GradeBookServer.Domain/Entities/Student.cs | 6 +- GradeBookServer.Domain/Entities/User.cs | 6 +- GradeBookServer.Domain/Entities/Vedomost.cs | 3 +- GradeBookServer.Domain/Interface/IHasId.cs | 13 ++ .../Repositories/BaseRepository.cs | 25 +++- .../Controllers/DirectionsController.cs | 53 ++++++++ .../Controllers/DisciplineController.cs | 56 +++++++++ .../Controllers/FacultyController.cs | 57 +++++++++ .../Controllers/GroupsController.cs | 53 ++++++++ .../Controllers/StudentController.cs | 2 +- GradeBookServer.WebAPI/Program.cs | 5 + 37 files changed, 882 insertions(+), 82 deletions(-) create mode 100644 GradeBookServer.Application/DTOs/Direction/DirectionCreateDto.cs create mode 100644 GradeBookServer.Application/DTOs/Direction/DirectionDetailDto.cs create mode 100644 GradeBookServer.Application/DTOs/Direction/DirectionTableDto.cs create mode 100644 GradeBookServer.Application/DTOs/Discipline/DisciplineCreateDto.cs create mode 100644 GradeBookServer.Application/DTOs/Discipline/DisciplineDetailDto.cs create mode 100644 GradeBookServer.Application/DTOs/Discipline/DisciplineTableDto.cs create mode 100644 GradeBookServer.Application/DTOs/Faculty/FacultyCreateDto.cs create mode 100644 GradeBookServer.Application/DTOs/Faculty/FacultyReadDto.cs create mode 100644 GradeBookServer.Application/DTOs/Group/GroupCreateDto.cs create mode 100644 GradeBookServer.Application/DTOs/Group/GroupDetailDto.cs create mode 100644 GradeBookServer.Application/DTOs/Group/GroupTableDto.cs delete mode 100644 GradeBookServer.Application/DTOs/Student/GradeInStudentDto.cs delete mode 100644 GradeBookServer.Application/DTOs/Student/StudentTableDto.cs create mode 100644 GradeBookServer.Application/Services/DirectionService.cs create mode 100644 GradeBookServer.Application/Services/DisciplineService.cs create mode 100644 GradeBookServer.Application/Services/FacultyService.cs create mode 100644 GradeBookServer.Application/Services/GroupService.cs create mode 100644 GradeBookServer.Domain/Interface/IHasId.cs create mode 100644 GradeBookServer.WebAPI/Controllers/DirectionsController.cs create mode 100644 GradeBookServer.WebAPI/Controllers/DisciplineController.cs create mode 100644 GradeBookServer.WebAPI/Controllers/FacultyController.cs create mode 100644 GradeBookServer.WebAPI/Controllers/GroupsController.cs diff --git a/GradeBookServer.Application/DTOs/Direction/DirectionCreateDto.cs b/GradeBookServer.Application/DTOs/Direction/DirectionCreateDto.cs new file mode 100644 index 0000000..7f274a4 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Direction/DirectionCreateDto.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Direction +{ + public class DirectionCreateDto + { + public required string Name { get; set; } + public int FacultyID { get; set; } + public List DisciplinIds { get; set; } = new List(); + public List GroupIds { get; set; } = new List(); + } +} diff --git a/GradeBookServer.Application/DTOs/Direction/DirectionDetailDto.cs b/GradeBookServer.Application/DTOs/Direction/DirectionDetailDto.cs new file mode 100644 index 0000000..c426311 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Direction/DirectionDetailDto.cs @@ -0,0 +1,19 @@ +using GradeBookServer.Application.DTOs.Discipline; +using GradeBookServer.Application.DTOs.Group; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Direction +{ + public class DirectionDetailDto + { + public int ID { get; set; } + public required string Name { get; set; } + public required string FacultyName { get; set; } + public List Disciplines { get; set; } = new(); + public List Groups { get; set; } = new(); + } +} diff --git a/GradeBookServer.Application/DTOs/Direction/DirectionTableDto.cs b/GradeBookServer.Application/DTOs/Direction/DirectionTableDto.cs new file mode 100644 index 0000000..cb9e07b --- /dev/null +++ b/GradeBookServer.Application/DTOs/Direction/DirectionTableDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Direction +{ + public class DirectionTableDto + { + public int ID { get; set; } + public required string Name { get; set; } + public string? FacultyName { get; set; } + } +} diff --git a/GradeBookServer.Application/DTOs/Discipline/DisciplineCreateDto.cs b/GradeBookServer.Application/DTOs/Discipline/DisciplineCreateDto.cs new file mode 100644 index 0000000..f703fee --- /dev/null +++ b/GradeBookServer.Application/DTOs/Discipline/DisciplineCreateDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Discipline +{ + public class DisciplineCreateDto + { + public required string Name { get; set; } + public int Hours { get; set; } + public List DirectionIds { get; set; } = new List(); + } +} diff --git a/GradeBookServer.Application/DTOs/Discipline/DisciplineDetailDto.cs b/GradeBookServer.Application/DTOs/Discipline/DisciplineDetailDto.cs new file mode 100644 index 0000000..ac53bac --- /dev/null +++ b/GradeBookServer.Application/DTOs/Discipline/DisciplineDetailDto.cs @@ -0,0 +1,17 @@ +using GradeBookServer.Application.DTOs.Direction; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Discipline +{ + public class DisciplineDetailDto + { + public int ID { get; set; } + public required string Name { get; set; } + public int Hours { get; set; } + public List Directions { get; set; } = new List(); + } +} diff --git a/GradeBookServer.Application/DTOs/Discipline/DisciplineTableDto.cs b/GradeBookServer.Application/DTOs/Discipline/DisciplineTableDto.cs new file mode 100644 index 0000000..ee4a57b --- /dev/null +++ b/GradeBookServer.Application/DTOs/Discipline/DisciplineTableDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Discipline +{ + public class DisciplineTableDto + { + public int ID { get; set; } + public required string Name { get; set; } + public int Hours { get; set; } + } +} diff --git a/GradeBookServer.Application/DTOs/Faculty/FacultyCreateDto.cs b/GradeBookServer.Application/DTOs/Faculty/FacultyCreateDto.cs new file mode 100644 index 0000000..e8cab27 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Faculty/FacultyCreateDto.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Faculty +{ + public class FacultyCreateDto + { + public required string Name { get; set; } + public List DirectionIds { get; set; } = new List(); + } +} diff --git a/GradeBookServer.Application/DTOs/Faculty/FacultyReadDto.cs b/GradeBookServer.Application/DTOs/Faculty/FacultyReadDto.cs new file mode 100644 index 0000000..65f8405 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Faculty/FacultyReadDto.cs @@ -0,0 +1,16 @@ +using GradeBookServer.Application.DTOs.Direction; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Faculty +{ + public class FacultyReadDto + { + public int ID { get; set; } + public required string Name { get; set; } + public List Directions { get; set; } = new List(); + } +} diff --git a/GradeBookServer.Application/DTOs/Group/GroupCreateDto.cs b/GradeBookServer.Application/DTOs/Group/GroupCreateDto.cs new file mode 100644 index 0000000..68907e5 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Group/GroupCreateDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Group +{ + public class GroupCreateDto + { + public required string Name { get; set; } + public int DirectionID { get; set; } + public List StudentIds { get; set; } = new(); + } +} diff --git a/GradeBookServer.Application/DTOs/Group/GroupDetailDto.cs b/GradeBookServer.Application/DTOs/Group/GroupDetailDto.cs new file mode 100644 index 0000000..413429b --- /dev/null +++ b/GradeBookServer.Application/DTOs/Group/GroupDetailDto.cs @@ -0,0 +1,17 @@ +using GradeBookServer.Application.DTOs.Student; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Group +{ + public class GroupDetailDto + { + public int ID { get; set; } + public required string Name { get; set; } + public required string DirectionName { get; set; } + public List Students { get; set; } = new(); + } +} diff --git a/GradeBookServer.Application/DTOs/Group/GroupTableDto.cs b/GradeBookServer.Application/DTOs/Group/GroupTableDto.cs new file mode 100644 index 0000000..b9900d5 --- /dev/null +++ b/GradeBookServer.Application/DTOs/Group/GroupTableDto.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.DTOs.Group +{ + public class GroupTableDto + { + public int ID { get; set; } + public required string Name { get; set; } + } +} diff --git a/GradeBookServer.Application/DTOs/Student/GradeInStudentDto.cs b/GradeBookServer.Application/DTOs/Student/GradeInStudentDto.cs deleted file mode 100644 index 5ed64b8..0000000 --- a/GradeBookServer.Application/DTOs/Student/GradeInStudentDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -using GradeBookServer.Domain.Enums; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GradeBookServer.Application.DTOs.Student -{ - public class GradeInStudentDto - { - public int ID { get; set; } - public GradeValue GradeValue { get; set; } - - public int VedomostID { get; set; } - public string DisciplineName { get; set; } = string.Empty; - public int Semester { get; set; } - public DateOnly AcademicYear { get; set; } - } - -} diff --git a/GradeBookServer.Application/DTOs/Student/StudentCreateDto.cs b/GradeBookServer.Application/DTOs/Student/StudentCreateDto.cs index f2e298f..3c92b30 100644 --- a/GradeBookServer.Application/DTOs/Student/StudentCreateDto.cs +++ b/GradeBookServer.Application/DTOs/Student/StudentCreateDto.cs @@ -12,5 +12,4 @@ namespace GradeBookServer.Application.DTOs.Student public int Age { get; set; } public int GroupID { get; set; } } - } diff --git a/GradeBookServer.Application/DTOs/Student/StudentReadDto.cs b/GradeBookServer.Application/DTOs/Student/StudentReadDto.cs index 843cda5..1ea4ee0 100644 --- a/GradeBookServer.Application/DTOs/Student/StudentReadDto.cs +++ b/GradeBookServer.Application/DTOs/Student/StudentReadDto.cs @@ -11,11 +11,7 @@ namespace GradeBookServer.Application.DTOs.Student public int ID { get; set; } public required string FullName { get; set; } public int Age { get; set; } - - public int GroupID { get; set; } public string? GroupName { get; set; } - - public List Grades { get; set; } = new(); } } diff --git a/GradeBookServer.Application/DTOs/Student/StudentTableDto.cs b/GradeBookServer.Application/DTOs/Student/StudentTableDto.cs deleted file mode 100644 index 537a2fd..0000000 --- a/GradeBookServer.Application/DTOs/Student/StudentTableDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GradeBookServer.Application.DTOs.Student -{ - public class StudentTableDto - { - public int ID { get; set; } - public required string FullName { get; set; } - public int Age { get; set; } - } -} diff --git a/GradeBookServer.Application/Interfaces/IBaseRepository.cs b/GradeBookServer.Application/Interfaces/IBaseRepository.cs index 652100a..2ebacb5 100644 --- a/GradeBookServer.Application/Interfaces/IBaseRepository.cs +++ b/GradeBookServer.Application/Interfaces/IBaseRepository.cs @@ -1,5 +1,6 @@ using GradeBookServer.Application.Common.Specifications; using GradeBookServer.Domain.Entities; +using GradeBookServer.Domain.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -9,13 +10,14 @@ using System.Threading.Tasks; namespace GradeBookServer.Application.Interfaces { - public interface IBaseRepository where TEntity : class + public interface IBaseRepository where TEntity : class, IHasId { Task GetByIdAsync(int id); - Task?> GetAllAsync(); + Task?> GetAllAsync(IncludeSpecification? includeSpec = null); Task AddAsync(TEntity entity); Task UpdateAsync(TEntity entity); Task DeleteAsync(int id); + Task> GetManyByIdsAsync(IEnumerable ids) where T : class, IHasId; Task GetByIdWithIncludeAsync (Expression> idSelector, IncludeSpecification? includeSpec = null); diff --git a/GradeBookServer.Application/Services/DirectionService.cs b/GradeBookServer.Application/Services/DirectionService.cs new file mode 100644 index 0000000..a1e30b6 --- /dev/null +++ b/GradeBookServer.Application/Services/DirectionService.cs @@ -0,0 +1,114 @@ +using GradeBookServer.Application.Common.Specifications; +using GradeBookServer.Application.DTOs.Direction; +using GradeBookServer.Application.DTOs.Discipline; +using GradeBookServer.Application.DTOs.Group; +using GradeBookServer.Application.Interfaces; +using GradeBookServer.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.Services +{ + public class DirectionService + { + private readonly IBaseRepository _baseRepository; + + public DirectionService(IBaseRepository baseRepository) + { + _baseRepository = baseRepository; + } + + public async Task GetDirectionByIdAsync(int id) + { + var direction = await _baseRepository.GetByIdWithIncludeAsync( + d => d.ID == id, + new IncludeSpecification( + d => d.Faculty!, + d => d.Disciplines, + d => d.Groups + )); + + if (direction == null) + return null; + + return new DirectionDetailDto + { + ID = direction.ID, + Name = direction.Name, + FacultyName = direction.Faculty?.Name ?? "—", + Disciplines = direction.Disciplines.Select(x => new DisciplineTableDto { ID = x.ID, Name = x.Name, Hours = x.TotalHours}).ToList(), + Groups = direction.Groups.Select(g => new GroupTableDto { ID = g.ID, Name = g.Name}).ToList() + }; + } + + public async Task?> GetAllDirectionsAsync() + { + var directions = await _baseRepository.GetAllAsync( + new IncludeSpecification(d => d.Faculty!) + ); + + if (directions == null) + return null; + + return directions.Select(d => new DirectionTableDto + { + ID = d.ID, + Name = d.Name, + FacultyName = d.Faculty?.Name ?? "—" + }); + } + + public async Task AddDirectionAsync(DirectionCreateDto dto) + { + var disciplins = await _baseRepository.GetManyByIdsAsync(dto.DisciplinIds); + var groups = await _baseRepository.GetManyByIdsAsync(dto.GroupIds); + + var direction = new Direction + { + Name = dto.Name, + FacultyID = dto.FacultyID, + Disciplines = disciplins.ToList(), + Groups = groups.ToList() + }; + + await _baseRepository.AddAsync(direction); + } + + public async Task UpdateDirectionAsync(int id, DirectionCreateDto dto) + { + var direction = await _baseRepository.GetByIdWithIncludeAsync( + d => d.ID == id, + new IncludeSpecification( + d => d.Disciplines!, + d => d.Groups! + ) + ); + + if (direction == null) return; + + var disciplines = await _baseRepository.GetManyByIdsAsync(dto.DisciplinIds); + var groups = await _baseRepository.GetManyByIdsAsync(dto.GroupIds); + + direction.Name = dto.Name; + direction.FacultyID = dto.FacultyID; + + direction.Disciplines.Clear(); + foreach (var d in disciplines) + direction.Disciplines.Add(d); + + direction.Groups.Clear(); + foreach (var g in groups) + direction.Groups.Add(g); + + await _baseRepository.UpdateAsync(direction); + } + + public async Task DeleteDirectionAsync(int id) + { + await _baseRepository.DeleteAsync(id); + } + } +} diff --git a/GradeBookServer.Application/Services/DisciplineService.cs b/GradeBookServer.Application/Services/DisciplineService.cs new file mode 100644 index 0000000..6bc1717 --- /dev/null +++ b/GradeBookServer.Application/Services/DisciplineService.cs @@ -0,0 +1,95 @@ +using GradeBookServer.Application.Common.Specifications; +using GradeBookServer.Application.DTOs.Direction; +using GradeBookServer.Application.DTOs.Discipline; +using GradeBookServer.Application.Interfaces; +using GradeBookServer.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.Services +{ + public class DisciplineService + { + private readonly IBaseRepository _baseRepository; + + public DisciplineService(IBaseRepository baseRepository) + { + _baseRepository = baseRepository; + } + + public async Task GetDisciplineByIdAsync(int id) + { + var discipline = await _baseRepository.GetByIdWithIncludeAsync( + d => d.ID == id, + new IncludeSpecification(d => d.Directions!) + ); + + if (discipline == null) + return null; + + return new DisciplineDetailDto + { + ID = discipline.ID, + Name = discipline.Name, + Hours = discipline.TotalHours, + Directions = discipline.Directions.Select(d => new DirectionTableDto + { + ID = d.ID, + Name = d.Name, + FacultyName = d.Faculty?.Name ?? "—" + }).ToList() + }; + } + + public async Task?> GetAllDisciplinesAsync() + { + var disciplines = await _baseRepository.GetAllAsync(); + + if (disciplines == null) + return null; + + return disciplines.Select(d => new DisciplineTableDto + { + ID = d.ID, + Name = d.Name, + Hours = d.TotalHours + }); + } + + public async Task AddDisciplineAsync(DisciplineCreateDto dto) + { + var directions = await _baseRepository.GetManyByIdsAsync(dto.DirectionIds); + + var discipline = new Discipline + { + Name = dto.Name, + TotalHours = dto.Hours, + Directions = directions.ToList() + }; + + await _baseRepository.AddAsync(discipline); + } + + public async Task UpdateDisciplineAsync(int id, DisciplineCreateDto dto) + { + var discipline = await _baseRepository.GetByIdAsync(id); + if (discipline == null) return; + + var directions = await _baseRepository.GetManyByIdsAsync(dto.DirectionIds); + + discipline.Name = dto.Name; + discipline.TotalHours = dto.Hours; + discipline.Directions = directions.ToList(); + + await _baseRepository.UpdateAsync(discipline); + } + + public async Task DeleteDisciplineAsync(int id) + { + await _baseRepository.DeleteAsync(id); + } + } +} diff --git a/GradeBookServer.Application/Services/FacultyService.cs b/GradeBookServer.Application/Services/FacultyService.cs new file mode 100644 index 0000000..cc1e328 --- /dev/null +++ b/GradeBookServer.Application/Services/FacultyService.cs @@ -0,0 +1,107 @@ +using GradeBookServer.Application.Common.Specifications; +using GradeBookServer.Application.DTOs.Direction; +using GradeBookServer.Application.DTOs.Faculty; +using GradeBookServer.Application.DTOs.Student; +using GradeBookServer.Application.Interfaces; +using GradeBookServer.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.Services +{ + public class FacultyService + { + private readonly IBaseRepository _baseRepository; + + public FacultyService(IBaseRepository baseRepository) + { + _baseRepository = baseRepository; + } + + public async Task GetFacultyByIdAsync(int id) + { + var faculty = await _baseRepository.GetByIdWithIncludeAsync( + f => f.ID == id, + new IncludeSpecification(f => f.Directions!) + ); + + if (faculty == null) + return null; + + return new FacultyReadDto + { + ID = faculty.ID, + Name = faculty.Name, + Directions = faculty.Directions.Select( + d => new DirectionTableDto { ID = d.ID, Name = d.Name, FacultyName = null} + ).ToList() + }; + } + + public async Task?> GetAllFacultiesAsync() + { + var faculties = await _baseRepository.GetAllAsync( + new IncludeSpecification(f => f.Directions!) + ); + + if (faculties == null) + return null; + + return faculties.Select(f => new FacultyReadDto + { + ID = f.ID, + Name = f.Name, + Directions = f.Directions.Select(d => new DirectionTableDto { ID = d.ID, Name = d.Name, FacultyName = null } + ).ToList() + }); + } + + public async Task AddFacultyAsync(FacultyCreateDto facultyDto) + { + var directions = await _baseRepository.GetManyByIdsAsync(facultyDto.DirectionIds); + + var faculty = new Faculty + { + Name = facultyDto.Name, + Directions = directions.ToList() + }; + + await _baseRepository.AddAsync(faculty); + } + + public async Task UpdateFacultyAsync(int id, FacultyCreateDto facultyDto) + { + var faculty = await _baseRepository.GetByIdWithIncludeAsync( + f => f.ID == id, + new IncludeSpecification(f => f.Directions!) + ); + + if (faculty == null) + return false; + + faculty.Name = facultyDto.Name; + + var directions = await _baseRepository.GetManyByIdsAsync(facultyDto.DirectionIds); + + faculty.Directions.Clear(); + foreach (var dir in directions) + faculty.Directions.Add(dir); + + await _baseRepository.UpdateAsync(faculty); + return true; + } + + public async Task DeleteFacultyAsync(int id) + { + var faculty = await _baseRepository.GetByIdAsync(id); + if (faculty == null) + return false; + + await _baseRepository.DeleteAsync(id); + return true; + } + } +} diff --git a/GradeBookServer.Application/Services/GroupService.cs b/GradeBookServer.Application/Services/GroupService.cs new file mode 100644 index 0000000..4ab9cdf --- /dev/null +++ b/GradeBookServer.Application/Services/GroupService.cs @@ -0,0 +1,98 @@ +using GradeBookServer.Application.Common.Specifications; +using GradeBookServer.Application.DTOs.Group; +using GradeBookServer.Application.DTOs.Student; +using GradeBookServer.Application.Interfaces; +using GradeBookServer.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Application.Services +{ + public class GroupService + { + private readonly IBaseRepository _baseRepository; + + public GroupService(IBaseRepository baseRepository) + { + _baseRepository = baseRepository; + } + + public async Task GetGroupByIdAsync(int id) + { + var group = await _baseRepository.GetByIdWithIncludeAsync( + g => g.ID == id, + new IncludeSpecification(g => g.Students!, g => g.Direction!) + ); + + if (group == null) + return null; + + return new GroupDetailDto + { + ID = group.ID, + Name = group.Name, + DirectionName = group.Direction?.Name ?? "—", + Students = group.Students.Select(s => new StudentReadDto + { + ID = s.ID, + FullName = s.FullName, + Age = s.Age, + GroupName = null + }).ToList() + }; + } + + public async Task?> GetAllGroupsAsync() + { + var groups = await _baseRepository.GetAllAsync(); + + if (groups == null) + return null; + + return groups.Select(g => new GroupTableDto + { + ID = g.ID, + Name = g.Name + }); + } + + public async Task AddGroupAsync(GroupCreateDto dto) + { + var students = await _baseRepository.GetManyByIdsAsync(dto.StudentIds); + + var group = new Group + { + Name = dto.Name, + DirectionID = dto.DirectionID, + Students = students.ToList() + }; + + await _baseRepository.AddAsync(group); + } + + public async Task UpdateGroupAsync(int id, GroupCreateDto dto) + { + var group = await _baseRepository.GetByIdAsync(id); + if (group == null) return; + + group.Name = dto.Name; + group.DirectionID = dto.DirectionID; + + var students = await _baseRepository.GetManyByIdsAsync(dto.StudentIds); + + group.Students.Clear(); + foreach (var s in students) + group.Students.Add(s); + + await _baseRepository.UpdateAsync(group); + } + + public async Task DeleteGroupAsync(int id) + { + await _baseRepository.DeleteAsync(id); + } + } +} diff --git a/GradeBookServer.Application/Services/StudentService.cs b/GradeBookServer.Application/Services/StudentService.cs index 78aa260..3b40647 100644 --- a/GradeBookServer.Application/Services/StudentService.cs +++ b/GradeBookServer.Application/Services/StudentService.cs @@ -23,12 +23,8 @@ namespace GradeBookServer.Application.Services { var student = await _baseRepository.GetByIdWithIncludeAsync( s => s.ID == id, - new IncludeSpecification( - s => s.Group!, - s => s.Grades, - s => s.Grades.Select(g => g.Vedomost), - s => s.Grades.Select(g => g.Vedomost!.Discipline) - )); + new IncludeSpecification(s => s.Group!) + ); if (student == null) return null; @@ -39,29 +35,24 @@ namespace GradeBookServer.Application.Services FullName = student.FullName, Age = student.Age, GroupName = student.Group?.Name ?? "—", - Grades = student.Grades.Select(g => new GradeInStudentDto - { - ID = g.ID, - GradeValue = g.GradeValue, - DisciplineName = g.Vedomost?.Discipline?.Name ?? "Не указано", - Semester = g.Vedomost?.Semester ?? 0, - AcademicYear = g.Vedomost?.AcademicYear ?? default - }).ToList() }; } - public async Task?> GetAllStudentsAsync() + public async Task?> GetAllStudentsAsync() { - var students = await _baseRepository.GetAllAsync(); + var students = await _baseRepository.GetAllAsync( + new IncludeSpecification(s => s.Group!) + ); if (students == null) return null; - return students.Select(s => new StudentTableDto + return students.Select(s => new StudentReadDto { ID = s.ID, FullName = s.FullName, - Age = s.Age + Age = s.Age, + GroupName = s.Group?.Name ?? "—", }); } diff --git a/GradeBookServer.Domain/Entities/Direction.cs b/GradeBookServer.Domain/Entities/Direction.cs index 850cd91..431e4f5 100644 --- a/GradeBookServer.Domain/Entities/Direction.cs +++ b/GradeBookServer.Domain/Entities/Direction.cs @@ -1,4 +1,5 @@ -using System; +using GradeBookServer.Domain.Interface; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -7,7 +8,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Direction + public class Direction : IHasId { public int ID { get; set; } public required string Name { get; set; } diff --git a/GradeBookServer.Domain/Entities/Discipline.cs b/GradeBookServer.Domain/Entities/Discipline.cs index bc4d7e3..2eae129 100644 --- a/GradeBookServer.Domain/Entities/Discipline.cs +++ b/GradeBookServer.Domain/Entities/Discipline.cs @@ -1,4 +1,5 @@ -using System; +using GradeBookServer.Domain.Interface; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +7,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Discipline + public class Discipline : IHasId { public int ID { get; set; } public required string Name { get; set; } @@ -15,5 +16,4 @@ namespace GradeBookServer.Domain.Entities public ICollection Directions { get; set; } = new List(); public ICollection Vedomosti { get; set; } = new List(); } - } diff --git a/GradeBookServer.Domain/Entities/Faculty.cs b/GradeBookServer.Domain/Entities/Faculty.cs index 3e4e2b4..f6816ea 100644 --- a/GradeBookServer.Domain/Entities/Faculty.cs +++ b/GradeBookServer.Domain/Entities/Faculty.cs @@ -1,4 +1,5 @@ -using System; +using GradeBookServer.Domain.Interface; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +7,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Faculty + public class Faculty : IHasId { public int ID { get; set; } public required string Name { get; set; } diff --git a/GradeBookServer.Domain/Entities/Grade.cs b/GradeBookServer.Domain/Entities/Grade.cs index f8c5af7..b549e6a 100644 --- a/GradeBookServer.Domain/Entities/Grade.cs +++ b/GradeBookServer.Domain/Entities/Grade.cs @@ -1,4 +1,5 @@ using GradeBookServer.Domain.Enums; +using GradeBookServer.Domain.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -7,7 +8,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Grade + public class Grade : IHasId { public int ID { get; set; } diff --git a/GradeBookServer.Domain/Entities/Group.cs b/GradeBookServer.Domain/Entities/Group.cs index 7602b92..949dd1e 100644 --- a/GradeBookServer.Domain/Entities/Group.cs +++ b/GradeBookServer.Domain/Entities/Group.cs @@ -1,4 +1,5 @@ -using System; +using GradeBookServer.Domain.Interface; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +7,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Group + public class Group : IHasId { public int ID { get; set; } public required string Name { get; set; } diff --git a/GradeBookServer.Domain/Entities/Student.cs b/GradeBookServer.Domain/Entities/Student.cs index 569c69d..abc10b3 100644 --- a/GradeBookServer.Domain/Entities/Student.cs +++ b/GradeBookServer.Domain/Entities/Student.cs @@ -1,4 +1,5 @@ -using System; +using GradeBookServer.Domain.Interface; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +7,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Student + public class Student : IHasId { public int ID { get; set; } public required string FullName { get; set; } @@ -17,5 +18,4 @@ namespace GradeBookServer.Domain.Entities public ICollection Grades { get; set; } = new List(); } - } diff --git a/GradeBookServer.Domain/Entities/User.cs b/GradeBookServer.Domain/Entities/User.cs index 337a49f..66b645c 100644 --- a/GradeBookServer.Domain/Entities/User.cs +++ b/GradeBookServer.Domain/Entities/User.cs @@ -1,4 +1,5 @@ using GradeBookServer.Domain.Enums; +using GradeBookServer.Domain.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -7,9 +8,9 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class User + public class User : IHasId { - public int Id { get; set; } + public int ID { get; set; } public required string Name { get; set; } public required string Email { get; set; } public string? PhoneNumber { get; set; } @@ -17,6 +18,5 @@ namespace GradeBookServer.Domain.Entities public UserRole Role { get; set; } public ICollection Vedomosti { get; set; } = new List(); - } } diff --git a/GradeBookServer.Domain/Entities/Vedomost.cs b/GradeBookServer.Domain/Entities/Vedomost.cs index e80cdda..4c0e81f 100644 --- a/GradeBookServer.Domain/Entities/Vedomost.cs +++ b/GradeBookServer.Domain/Entities/Vedomost.cs @@ -1,4 +1,5 @@ using GradeBookServer.Domain.Enums; +using GradeBookServer.Domain.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -7,7 +8,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Domain.Entities { - public class Vedomost + public class Vedomost : IHasId { public int ID { get; set; } public ExamType ExamType { get; set; } diff --git a/GradeBookServer.Domain/Interface/IHasId.cs b/GradeBookServer.Domain/Interface/IHasId.cs new file mode 100644 index 0000000..0d62f43 --- /dev/null +++ b/GradeBookServer.Domain/Interface/IHasId.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GradeBookServer.Domain.Interface +{ + public interface IHasId + { + int ID { get; } + } +} diff --git a/GradeBookServer.Infrastructure/Repositories/BaseRepository.cs b/GradeBookServer.Infrastructure/Repositories/BaseRepository.cs index 030493d..86b0712 100644 --- a/GradeBookServer.Infrastructure/Repositories/BaseRepository.cs +++ b/GradeBookServer.Infrastructure/Repositories/BaseRepository.cs @@ -1,6 +1,7 @@ using GradeBookServer.Application.Common.Specifications; using GradeBookServer.Application.Interfaces; using GradeBookServer.Domain.Entities; +using GradeBookServer.Domain.Interface; using GradeBookServer.Infrastructure.Specifications; using Microsoft.EntityFrameworkCore; using System; @@ -12,7 +13,7 @@ using System.Threading.Tasks; namespace GradeBookServer.Infrastructure.Repositories { - public class BaseRepository : IBaseRepository where TEntity : class + public class BaseRepository : IBaseRepository where TEntity : class, IHasId { protected readonly DbContext _context; protected readonly DbSet _dbSet; @@ -32,8 +33,18 @@ namespace GradeBookServer.Infrastructure.Repositories await _context.SaveChangesAsync(); } - public virtual async Task?> GetAllAsync() - => await _dbSet.ToListAsync(); + public async Task?> GetAllAsync(IncludeSpecification? includeSpec = null) + { + IQueryable query = _context.Set(); + + if (includeSpec is not null) + { + foreach (var include in includeSpec.Includes) + query = query.Include(include); + } + + return await query.ToListAsync(); + } public virtual async Task UpdateAsync(TEntity entity) { @@ -52,6 +63,14 @@ namespace GradeBookServer.Infrastructure.Repositories } } + public async Task> GetManyByIdsAsync(IEnumerable ids) where T : class, IHasId + { + var dbSet = _context.Set(); + + return await dbSet.Where(e => ids.Contains(e.ID)).ToListAsync(); + + } + public async Task GetByIdWithIncludeAsync (Expression> idSelector, IncludeSpecification? includeSpec = null) diff --git a/GradeBookServer.WebAPI/Controllers/DirectionsController.cs b/GradeBookServer.WebAPI/Controllers/DirectionsController.cs new file mode 100644 index 0000000..fa48f3b --- /dev/null +++ b/GradeBookServer.WebAPI/Controllers/DirectionsController.cs @@ -0,0 +1,53 @@ +using GradeBookServer.Application.DTOs.Direction; +using GradeBookServer.Application.Services; +using Microsoft.AspNetCore.Mvc; + +namespace GradeBookServer.WebAPI.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class DirectionsController : ControllerBase + { + private readonly DirectionService _directionService; + + public DirectionsController(DirectionService directionService) + { + _directionService = directionService; + } + + [HttpGet] + public async Task>> GetAll() + { + var directions = await _directionService.GetAllDirectionsAsync(); + return directions == null ? NotFound() : Ok(directions); + } + + [HttpGet("{id}")] + public async Task> GetById(int id) + { + var direction = await _directionService.GetDirectionByIdAsync(id); + return direction == null ? NotFound() : Ok(direction); + } + + [HttpPost] + public async Task Create(DirectionCreateDto dto) + { + await _directionService.AddDirectionAsync(dto); + return Ok(); + } + + [HttpPut("{id}")] + public async Task Update(int id, DirectionCreateDto dto) + { + await _directionService.UpdateDirectionAsync(id, dto); + return Ok(); + } + + [HttpDelete("{id}")] + public async Task Delete(int id) + { + await _directionService.DeleteDirectionAsync(id); + return Ok(); + } + } +} diff --git a/GradeBookServer.WebAPI/Controllers/DisciplineController.cs b/GradeBookServer.WebAPI/Controllers/DisciplineController.cs new file mode 100644 index 0000000..f3bd087 --- /dev/null +++ b/GradeBookServer.WebAPI/Controllers/DisciplineController.cs @@ -0,0 +1,56 @@ +using GradeBookServer.Application.DTOs.Discipline; +using GradeBookServer.Application.Services; +using Microsoft.AspNetCore.Mvc; + +namespace GradeBookServer.WebAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class DisciplineController : ControllerBase + { + private readonly DisciplineService _disciplineService; + + public DisciplineController(DisciplineService disciplineService) + { + _disciplineService = disciplineService; + } + + [HttpGet] + public async Task>> GetAllDisciplines() + { + var disciplines = await _disciplineService.GetAllDisciplinesAsync(); + return Ok(disciplines); + } + + [HttpGet("{id}")] + public async Task> GetDisciplineById(int id) + { + var discipline = await _disciplineService.GetDisciplineByIdAsync(id); + if (discipline == null) + return NotFound(); + + return Ok(discipline); + } + + [HttpPost] + public async Task AddDiscipline([FromBody] DisciplineCreateDto disciplineDto) + { + await _disciplineService.AddDisciplineAsync(disciplineDto); + return Ok(); + } + + [HttpPut("{id}")] + public async Task UpdateDiscipline(int id, [FromBody] DisciplineCreateDto disciplineDto) + { + await _disciplineService.UpdateDisciplineAsync(id, disciplineDto); + return NoContent(); + } + + [HttpDelete("{id}")] + public async Task DeleteDiscipline(int id) + { + await _disciplineService.DeleteDisciplineAsync(id); + return NoContent(); + } + } +} diff --git a/GradeBookServer.WebAPI/Controllers/FacultyController.cs b/GradeBookServer.WebAPI/Controllers/FacultyController.cs new file mode 100644 index 0000000..d8db1b7 --- /dev/null +++ b/GradeBookServer.WebAPI/Controllers/FacultyController.cs @@ -0,0 +1,57 @@ +using GradeBookServer.Application.DTOs.Faculty; +using GradeBookServer.Application.Services; +using Microsoft.AspNetCore.Mvc; + +namespace GradeBookServer.WebAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class FacultyController : ControllerBase + { + private readonly FacultyService _facultyService; + + public FacultyController(FacultyService facultyService) + { + _facultyService = facultyService; + } + + [HttpGet] + public async Task>> GetAllFaculties() + { + var faculties = await _facultyService.GetAllFacultiesAsync(); + return Ok(faculties); + } + + [HttpGet("{id}")] + public async Task> GetFacultyById(int id) + { + var faculty = await _facultyService.GetFacultyByIdAsync(id); + if (faculty == null) + { + return NotFound(); + } + return Ok(faculty); + } + + [HttpPost] + public async Task AddFaculty([FromBody] FacultyCreateDto facultyDto) + { + await _facultyService.AddFacultyAsync(facultyDto); + return CreatedAtAction(nameof(GetFacultyById), new { id = facultyDto.Name }, facultyDto); + } + + [HttpPut("{id}")] + public async Task UpdateFaculty(int id, [FromBody] FacultyCreateDto facultyDto) + { + await _facultyService.UpdateFacultyAsync(id, facultyDto); + return NoContent(); + } + + [HttpDelete("{id}")] + public async Task DeleteFaculty(int id) + { + await _facultyService.DeleteFacultyAsync(id); + return NoContent(); + } + } +} diff --git a/GradeBookServer.WebAPI/Controllers/GroupsController.cs b/GradeBookServer.WebAPI/Controllers/GroupsController.cs new file mode 100644 index 0000000..f642a67 --- /dev/null +++ b/GradeBookServer.WebAPI/Controllers/GroupsController.cs @@ -0,0 +1,53 @@ +using GradeBookServer.Application.DTOs.Group; +using GradeBookServer.Application.Services; +using Microsoft.AspNetCore.Mvc; + +namespace GradeBookServer.WebAPI.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class GroupsController : ControllerBase + { + private readonly GroupService _groupService; + + public GroupsController(GroupService groupService) + { + _groupService = groupService; + } + + [HttpGet] + public async Task>> GetAll() + { + var groups = await _groupService.GetAllGroupsAsync(); + return groups == null ? NotFound() : Ok(groups); + } + + [HttpGet("{id}")] + public async Task> GetById(int id) + { + var group = await _groupService.GetGroupByIdAsync(id); + return group == null ? NotFound() : Ok(group); + } + + [HttpPost] + public async Task Create(GroupCreateDto dto) + { + await _groupService.AddGroupAsync(dto); + return Ok(); + } + + [HttpPut("{id}")] + public async Task Update(int id, GroupCreateDto dto) + { + await _groupService.UpdateGroupAsync(id, dto); + return Ok(); + } + + [HttpDelete("{id}")] + public async Task Delete(int id) + { + await _groupService.DeleteGroupAsync(id); + return Ok(); + } + } +} diff --git a/GradeBookServer.WebAPI/Controllers/StudentController.cs b/GradeBookServer.WebAPI/Controllers/StudentController.cs index bfa6c82..0294687 100644 --- a/GradeBookServer.WebAPI/Controllers/StudentController.cs +++ b/GradeBookServer.WebAPI/Controllers/StudentController.cs @@ -20,7 +20,7 @@ namespace WebAPI.Controllers } [HttpGet] - public async Task>> GetAllStudents() + public async Task>> GetAllStudents() { var students = await _studentService.GetAllStudentsAsync(); return Ok(students); diff --git a/GradeBookServer.WebAPI/Program.cs b/GradeBookServer.WebAPI/Program.cs index d757520..953a8a1 100644 --- a/GradeBookServer.WebAPI/Program.cs +++ b/GradeBookServer.WebAPI/Program.cs @@ -30,6 +30,11 @@ builder.Services.AddSwaggerGen(options => builder.Services.AddScoped(); builder.Services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>)); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddControllers();