diff --git a/ApiDto/ApiDto.csproj b/ApiDto/ApiDto.csproj
new file mode 100644
index 0000000..f806393
--- /dev/null
+++ b/ApiDto/ApiDto.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+ disable
+ enable
+ Winsomnia
+ 1.0.0-a0
+ 1.0.0.0
+ 1.0.0.0
+ Mirea.Api.Dto
+ $(AssemblyName)
+ True
+ ApiDtoDocs.xml
+
+
+
+
+ Always
+
+
+
+
diff --git a/ApiDto/Requests/ScheduleRequest.cs b/ApiDto/Requests/ScheduleRequest.cs
new file mode 100644
index 0000000..476d8f3
--- /dev/null
+++ b/ApiDto/Requests/ScheduleRequest.cs
@@ -0,0 +1,37 @@
+namespace Mirea.Api.Dto.Requests;
+
+///
+/// Represents a request object for retrieving schedules based on various filters.
+///
+public class ScheduleRequest
+{
+ ///
+ /// Gets or sets an array of group IDs.
+ ///
+ /// This array can contain null values.
+ public int[]? Groups { get; set; } = null;
+
+ ///
+ /// Gets or sets a value indicating whether to retrieve schedules for even weeks.
+ ///
+ /// This property can contain null.
+ public bool? IsEven { get; set; } = null;
+
+ ///
+ /// Gets or sets an array of discipline IDs.
+ ///
+ /// This array can contain null values.
+ public int[]? Disciplines { get; set; } = null;
+
+ ///
+ /// Gets or sets an array of professor IDs.
+ ///
+ /// This array can contain null values.
+ public int[]? Professors { get; set; } = null;
+
+ ///
+ /// Gets or sets an array of lecture hall IDs.
+ ///
+ /// This array can contain null values.
+ public int[]? LectureHalls { get; set; } = null;
+}
diff --git a/ApiDto/Responses/CampusBasicInfoResponse.cs b/ApiDto/Responses/CampusBasicInfoResponse.cs
new file mode 100644
index 0000000..4ad46a7
--- /dev/null
+++ b/ApiDto/Responses/CampusBasicInfoResponse.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents basic information about a campus.
+///
+public class CampusBasicInfoResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the campus.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the code name of the campus.
+ ///
+ [Required]
+ public required string CodeName { get; set; }
+
+ ///
+ /// Gets or sets the full name of the campus (optional).
+ ///
+ public string? FullName { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/CampusDetailsResponse.cs b/ApiDto/Responses/CampusDetailsResponse.cs
new file mode 100644
index 0000000..82db94e
--- /dev/null
+++ b/ApiDto/Responses/CampusDetailsResponse.cs
@@ -0,0 +1,31 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents detailed information about a campus.
+///
+public class CampusDetailsResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the campus.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the code name of the campus.
+ ///
+ [Required]
+ public required string CodeName { get; set; }
+
+ ///
+ /// Gets or sets the full name of the campus (optional).
+ ///
+ public string? FullName { get; set; }
+
+ ///
+ /// Gets or sets the address of the campus (optional).
+ ///
+ public string? Address { get; set; }
+}
diff --git a/ApiDto/Responses/DisciplineResponse.cs b/ApiDto/Responses/DisciplineResponse.cs
new file mode 100644
index 0000000..9b35e13
--- /dev/null
+++ b/ApiDto/Responses/DisciplineResponse.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents information about a discipline.
+///
+public class DisciplineResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the discipline.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline.
+ ///
+ [Required]
+ public required string Name { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/ErrorResponse.cs b/ApiDto/Responses/ErrorResponse.cs
new file mode 100644
index 0000000..f0dc33c
--- /dev/null
+++ b/ApiDto/Responses/ErrorResponse.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// A class for providing information about an error
+///
+public class ErrorResponse
+{
+ ///
+ /// The text or translation code of the error. This field may not contain information in specific scenarios.
+ /// For example, it might be empty for HTTP 204 responses where no content is returned or if the validation texts have not been configured.
+ ///
+ [Required]
+ public required string Error { get; set; }
+ ///
+ /// In addition to returning the response code in the header, it is also duplicated in this field.
+ /// Represents the HTTP response code.
+ ///
+ [Required]
+ public required int Code { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/FacultyDetailsResponse.cs b/ApiDto/Responses/FacultyDetailsResponse.cs
new file mode 100644
index 0000000..09c863b
--- /dev/null
+++ b/ApiDto/Responses/FacultyDetailsResponse.cs
@@ -0,0 +1,36 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents detailed information about a faculty.
+///
+public class FacultyDetailsResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the faculty.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the faculty.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier of the campus to which the faculty belongs (optional).
+ ///
+ public int? CampusId { get; set; }
+
+ ///
+ /// Gets or sets the name of the campus to which the faculty belongs (optional).
+ ///
+ public string? CampusName { get; set; }
+
+ ///
+ /// Gets or sets the code name of the campus to which the faculty belongs (optional).
+ ///
+ public string? CampusCode { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/FacultyResponse.cs b/ApiDto/Responses/FacultyResponse.cs
new file mode 100644
index 0000000..adcf127
--- /dev/null
+++ b/ApiDto/Responses/FacultyResponse.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents basic information about a faculty.
+///
+public class FacultyResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the faculty.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the faculty.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier of the campus to which the faculty belongs (optional).
+ ///
+ public int? CampusId { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/GroupDetailsResponse.cs b/ApiDto/Responses/GroupDetailsResponse.cs
new file mode 100644
index 0000000..44670fe
--- /dev/null
+++ b/ApiDto/Responses/GroupDetailsResponse.cs
@@ -0,0 +1,37 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents detailed information about a group.
+///
+public class GroupDetailsResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the group.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the group.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the course number of the group.
+ ///
+ [Required]
+ public int CourseNumber { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier of the faculty to which the group belongs (optional).
+ ///
+ public int? FacultyId { get; set; }
+
+ ///
+ /// Gets or sets the name of the faculty to which the group belongs (optional).
+ ///
+ public string? FacultyName { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/GroupResponse.cs b/ApiDto/Responses/GroupResponse.cs
new file mode 100644
index 0000000..0177459
--- /dev/null
+++ b/ApiDto/Responses/GroupResponse.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents basic information about a group.
+///
+public class GroupResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the group.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the group.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the course number of the group.
+ ///
+ [Required]
+ public int CourseNumber { get; set; }
+
+ ///
+ /// Gets or sets the unique identifier of the faculty to which the group belongs (optional).
+ ///
+ public int? FacultyId { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/LectureHallDetailsResponse.cs b/ApiDto/Responses/LectureHallDetailsResponse.cs
new file mode 100644
index 0000000..67b1a66
--- /dev/null
+++ b/ApiDto/Responses/LectureHallDetailsResponse.cs
@@ -0,0 +1,37 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents the detailed response model for a lecture hall.
+///
+public class LectureHallDetailsResponse
+{
+ ///
+ /// Gets or sets the ID of the lecture hall.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the lecture hall.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the ID of the campus to which the lecture hall belongs.
+ ///
+ [Required]
+ public int CampusId { get; set; }
+
+ ///
+ /// Gets or sets the name of the campus.
+ ///
+ public string? CampusName { get; set; }
+
+ ///
+ /// Gets or sets the code of the campus.
+ ///
+ public string? CampusCode { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/LectureHallResponse.cs b/ApiDto/Responses/LectureHallResponse.cs
new file mode 100644
index 0000000..6bb288f
--- /dev/null
+++ b/ApiDto/Responses/LectureHallResponse.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents the response model for a lecture hall.
+///
+public class LectureHallResponse
+{
+ ///
+ /// Gets or sets the ID of the lecture hall.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the lecture hall.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the ID of the campus to which the lecture hall belongs.
+ ///
+ [Required]
+ public int CampusId { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/ProfessorResponse.cs b/ApiDto/Responses/ProfessorResponse.cs
new file mode 100644
index 0000000..02361f9
--- /dev/null
+++ b/ApiDto/Responses/ProfessorResponse.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses;
+
+///
+/// Represents information about a professor.
+///
+public class ProfessorResponse
+{
+ ///
+ /// Gets or sets the unique identifier of the professor.
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the name of the professor.
+ ///
+ [Required]
+ public required string Name { get; set; }
+
+ ///
+ /// Gets or sets the alternate name of the professor (optional).
+ ///
+ public string? AltName { get; set; }
+}
\ No newline at end of file
diff --git a/ApiDto/Responses/Schedule/DisciplineScheduleResponse.cs b/ApiDto/Responses/Schedule/DisciplineScheduleResponse.cs
new file mode 100644
index 0000000..bf4a337
--- /dev/null
+++ b/ApiDto/Responses/Schedule/DisciplineScheduleResponse.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses.Schedule;
+
+///
+/// Represents information about a specific schedule entry for a professor.
+///
+public class DisciplineScheduleInfo
+{
+ ///
+ /// Gets or sets the day of the week for the schedule entry.
+ ///
+ [Required]
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number for the schedule entry.
+ ///
+ [Required]
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ [Required]
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation for the schedule entry.
+ ///
+ [Required]
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the names of the group for the schedule entry.
+ ///
+ [Required]
+
+ public required string Group { get; set; }
+ ///
+ /// Gets or sets the IDs of the group for the schedule entry.
+ ///
+ [Required]
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the names of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the professors for the schedule entry.
+ ///
+ public required IEnumerable Professors { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the professors for the schedule entry.
+ ///
+ public required IEnumerable ProfessorsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses for the schedule entry.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses for the schedule entry.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings for the schedule entry.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
+
+///
+/// Represents a response containing schedule information for a professor.
+///
+public class DisciplineScheduleResponse
+{
+ ///
+ /// Gets or sets the name of the discipline.
+ ///
+ [Required]
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline.
+ ///
+ [Required]
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the schedules for the professor.
+ ///
+ [Required]
+ public required IEnumerable Schedules { get; set; }
+}
diff --git a/ApiDto/Responses/Schedule/GroupScheduleResponse.cs b/ApiDto/Responses/Schedule/GroupScheduleResponse.cs
new file mode 100644
index 0000000..7fa13d1
--- /dev/null
+++ b/ApiDto/Responses/Schedule/GroupScheduleResponse.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses.Schedule;
+
+///
+/// Represents information about a specific schedule entry for a group.
+///
+public class GroupScheduleInfo
+{
+ ///
+ /// Gets or sets the day of the week for the schedule entry.
+ ///
+ [Required]
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number for the schedule entry.
+ ///
+ [Required]
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ [Required]
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation for the schedule entry.
+ ///
+ [Required]
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the names of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the professors for the schedule entry.
+ ///
+ public required IEnumerable Professors { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the professors for the schedule entry.
+ ///
+ public required IEnumerable ProfessorsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses for the schedule entry.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses for the schedule entry.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings for the schedule entry.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
+
+///
+/// Represents a response containing schedule information for a group.
+///
+public class GroupScheduleResponse
+{
+ ///
+ /// Gets or sets the name of the group.
+ ///
+ [Required]
+ public required string Group { get; set; }
+
+ ///
+ /// Gets or sets the ID of the group.
+ ///
+ [Required]
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the schedules for the group.
+ ///
+ [Required]
+ public required IEnumerable Schedules { get; set; }
+}
diff --git a/ApiDto/Responses/Schedule/LectureHallScheduleResponse.cs b/ApiDto/Responses/Schedule/LectureHallScheduleResponse.cs
new file mode 100644
index 0000000..369a8f5
--- /dev/null
+++ b/ApiDto/Responses/Schedule/LectureHallScheduleResponse.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses.Schedule;
+
+///
+/// Represents information about a specific schedule entry for a lecture hall.
+///
+public class LectureHallScheduleInfo
+{
+ ///
+ /// Gets or sets the day of the week for the schedule entry.
+ ///
+ [Required]
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number for the schedule entry.
+ ///
+ [Required]
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ [Required]
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation for the schedule entry.
+ ///
+ [Required]
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the names of the group for the schedule entry.
+ ///
+ [Required]
+ public required string Group { get; set; }
+ ///
+ /// Gets or sets the IDs of the group for the schedule entry.
+ ///
+ [Required]
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses for the schedule entry.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses for the schedule entry.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the names of the professors for the schedule entry.
+ ///
+ public required IEnumerable Professors { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the professors for the schedule entry.
+ ///
+ public required IEnumerable ProfessorsId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings for the schedule entry.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
+
+///
+/// Represents a response containing schedule information for a lecture hall.
+///
+public class LectureHallScheduleResponse
+{
+ ///
+ /// Gets or sets the names of the lecture halls.
+ ///
+ public required string LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls.
+ ///
+ public required int LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the schedules for the lecture hall.
+ ///
+ [Required]
+ public required IEnumerable Schedules { get; set; }
+}
diff --git a/ApiDto/Responses/Schedule/ProfessorScheduleResponse.cs b/ApiDto/Responses/Schedule/ProfessorScheduleResponse.cs
new file mode 100644
index 0000000..3a53ebf
--- /dev/null
+++ b/ApiDto/Responses/Schedule/ProfessorScheduleResponse.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses.Schedule;
+
+///
+/// Represents information about a specific schedule entry for a professor.
+///
+public class ProfessorScheduleInfo
+{
+ ///
+ /// Gets or sets the day of the week for the schedule entry.
+ ///
+ [Required]
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number for the schedule entry.
+ ///
+ [Required]
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ [Required]
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation for the schedule entry.
+ ///
+ [Required]
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the names of the group for the schedule entry.
+ ///
+ [Required]
+
+ public required string Group { get; set; }
+ ///
+ /// Gets or sets the IDs of the group for the schedule entry.
+ ///
+ [Required]
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the names of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses for the schedule entry.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses for the schedule entry.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings for the schedule entry.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
+
+///
+/// Represents a response containing schedule information for a professor.
+///
+public class ProfessorScheduleResponse
+{
+ ///
+ /// Gets or sets the name of the professor.
+ ///
+ [Required]
+ public required string Professor { get; set; }
+
+ ///
+ /// Gets or sets the ID of the professor.
+ ///
+ [Required]
+ public required int ProfessorId { get; set; }
+
+ ///
+ /// Gets or sets the schedules for the professor.
+ ///
+ [Required]
+ public required IEnumerable Schedules { get; set; }
+}
diff --git a/ApiDto/Responses/Schedule/ScheduleResponse.cs b/ApiDto/Responses/Schedule/ScheduleResponse.cs
new file mode 100644
index 0000000..2a03178
--- /dev/null
+++ b/ApiDto/Responses/Schedule/ScheduleResponse.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Mirea.Api.Dto.Responses.Schedule;
+
+///
+/// Represents a response object containing schedule information.
+///
+public class ScheduleResponse
+{
+ ///
+ /// Gets or sets the day of the week for the schedule entry.
+ ///
+ [Required]
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number for the schedule entry.
+ ///
+ [Required]
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ [Required]
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline for the schedule entry.
+ ///
+ [Required]
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation for the schedule entry.
+ ///
+ [Required]
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the name of the group for the schedule entry.
+ ///
+ [Required]
+ public required string Group { get; set; }
+
+ ///
+ /// Gets or sets the ID of the group for the schedule entry.
+ ///
+ [Required]
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the names of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls for the schedule entry.
+ ///
+ public required IEnumerable LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the professors for the schedule entry.
+ ///
+ public required IEnumerable Professors { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the professors for the schedule entry.
+ ///
+ public required IEnumerable ProfessorsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses for the schedule entry.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses for the schedule entry.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings for the schedule entry.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
diff --git a/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQuery.cs b/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQuery.cs
new file mode 100644
index 0000000..939e1c6
--- /dev/null
+++ b/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQuery.cs
@@ -0,0 +1,12 @@
+using MediatR;
+
+namespace Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
+
+public class GetScheduleListQuery : IRequest
+{
+ public int[]? GroupIds { get; set; }
+ public int[]? DisciplineIds { get; set; }
+ public int[]? LectureHallIds { get; set; }
+ public int[]? ProfessorIds { get; set; }
+ public bool? IsEven { get; set; }
+}
\ No newline at end of file
diff --git a/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQueryHandler.cs b/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQueryHandler.cs
new file mode 100644
index 0000000..ba08003
--- /dev/null
+++ b/Application/Cqrs/Schedule/Queries/GetScheduleList/GetScheduleListQueryHandler.cs
@@ -0,0 +1,87 @@
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+using Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
+
+public class GetScheduleListQueryHandler(ILessonDbContext dbContext) : IRequestHandler
+{
+ public async Task Handle(GetScheduleListQuery request, CancellationToken cancellationToken)
+ {
+ var query = dbContext.Lessons.Include(l => l.LessonAssociations)
+ .ThenInclude(la => la.LectureHall)
+ .ThenInclude(lh => lh!.Campus)
+ .Include(l => l.LessonAssociations)
+ .ThenInclude(la => la.Professor)
+ .Include(l => l.Group)
+ .Include(l => l.TypeOfOccupation)
+ .Include(l => l.Discipline)
+ .AsQueryable();
+
+ if (request.IsEven != null)
+ query = query.Where(l => l.IsEven == request.IsEven);
+
+ if (request.GroupIds != null && request.GroupIds.Length != 0)
+ query = query.Where(l => request.GroupIds.Contains(l.GroupId));
+
+ if (request.DisciplineIds != null && request.DisciplineIds.Length != 0)
+ query = query.Where(l => request.DisciplineIds.Contains(l.DisciplineId));
+
+ if (request.LectureHallIds != null && request.LectureHallIds.Length != 0)
+ query = query.Where(l => l.LessonAssociations!.Any(la =>
+ la.LectureHallId != null && request.LectureHallIds.Contains(la.LectureHallId.Value)));
+
+ if (request.ProfessorIds != null && request.ProfessorIds.Length != 0)
+ query = query.Where(l =>
+ l.LessonAssociations!.Any(la =>
+ la.ProfessorId != null && request.ProfessorIds.Contains(la.ProfessorId.Value)));
+
+ var data = await query.ToArrayAsync(cancellationToken);
+
+ var result = data.Select(l => new ScheduleLookupDto()
+ {
+ DayOfWeek = l.DayOfWeek,
+ PairNumber = l.PairNumber,
+ IsEven = l.IsEven,
+ TypeOfOccupation = l.TypeOfOccupation!.ShortName,
+
+ Discipline = l.Discipline!.Name,
+ DisciplineId = l.DisciplineId,
+
+ Group = l.Group!.Name,
+ GroupId = l.GroupId,
+
+ LectureHalls = l.LessonAssociations!
+ .Where(la => !string.IsNullOrEmpty(la.LectureHall?.Name))
+ .Select(la => la.LectureHall?.Name),
+ LectureHallsId = l.LessonAssociations!
+ .Where(la => la.LectureHallId != null)
+ .Select(la => la.LectureHallId),
+
+ Campus = l.LessonAssociations!
+ .Where(la => !string.IsNullOrEmpty(la.LectureHall?.Campus?.CodeName))
+ .Select(la => la.LectureHall?.Campus?.CodeName),
+ CampusId = l.LessonAssociations!
+ .Where(la => la.LectureHall?.Campus != null)
+ .Select(la => la.LectureHall?.CampusId),
+
+
+ Professors = l.LessonAssociations!
+ .Where(la => !string.IsNullOrEmpty(la.Professor?.Name))
+ .Select(la => la.Professor?.Name),
+ ProfessorsId = l.LessonAssociations!
+ .Where(la => la.ProfessorId != null)
+ .Select(la => la.ProfessorId),
+
+ LinkToMeet = l.LessonAssociations!.Select(la => la.LinkToMeet)
+ }).ToList();
+
+ return new ScheduleListVm
+ {
+ Schedules = result
+ };
+ }
+}
\ No newline at end of file
diff --git a/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleListVm.cs b/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleListVm.cs
new file mode 100644
index 0000000..565e5b9
--- /dev/null
+++ b/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleListVm.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
+
+///
+/// Represents a view model for a list of schedules.
+///
+public class ScheduleListVm
+{
+ ///
+ /// Gets or sets the list of schedules.
+ ///
+ public IList Schedules { get; set; } = new List();
+}
\ No newline at end of file
diff --git a/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleLookupDto.cs b/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleLookupDto.cs
new file mode 100644
index 0000000..bd3808f
--- /dev/null
+++ b/Application/Cqrs/Schedule/Queries/GetScheduleList/ScheduleLookupDto.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
+
+///
+/// Represents a data transfer object for schedule lookup.
+///
+public class ScheduleLookupDto
+{
+ ///
+ /// Gets or sets the day of the week.
+ ///
+ public DayOfWeek DayOfWeek { get; set; }
+
+ ///
+ /// Gets or sets the pair number.
+ ///
+ public int PairNumber { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the pair is on an even week.
+ ///
+ public bool IsEven { get; set; }
+
+ ///
+ /// Gets or sets the name of the discipline.
+ ///
+ public required string Discipline { get; set; }
+
+ ///
+ /// Gets or sets the ID of the discipline.
+ ///
+ public required int DisciplineId { get; set; }
+
+ ///
+ /// Gets or sets the type of occupation.
+ ///
+ public required string TypeOfOccupation { get; set; }
+
+ ///
+ /// Gets or sets the name of the group.
+ ///
+ public required string Group { get; set; }
+
+ ///
+ /// Gets or sets the ID of the group.
+ ///
+ public required int GroupId { get; set; }
+
+ ///
+ /// Gets or sets the names of the lecture halls.
+ ///
+ public required IEnumerable LectureHalls { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the lecture halls.
+ ///
+ public required IEnumerable LectureHallsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the professors.
+ ///
+ public required IEnumerable Professors { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the professors.
+ ///
+ public required IEnumerable ProfessorsId { get; set; }
+
+ ///
+ /// Gets or sets the names of the campuses.
+ ///
+ public required IEnumerable Campus { get; set; }
+
+ ///
+ /// Gets or sets the IDs of the campuses.
+ ///
+ public required IEnumerable CampusId { get; set; }
+
+ ///
+ /// Gets or sets the links to online meetings.
+ ///
+ public required IEnumerable LinkToMeet { get; set; }
+}
\ No newline at end of file
diff --git a/Endpoint/Common/Attributes/BadRequestResponseAttribute.cs b/Endpoint/Common/Attributes/BadRequestResponseAttribute.cs
new file mode 100644
index 0000000..85f9ed8
--- /dev/null
+++ b/Endpoint/Common/Attributes/BadRequestResponseAttribute.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.Dto.Responses;
+using System;
+
+namespace Mirea.Api.Endpoint.Common.Attributes;
+
+[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
+public class BadRequestResponseAttribute() : ProducesResponseTypeAttribute(typeof(ErrorResponse), StatusCodes.Status400BadRequest);
\ No newline at end of file
diff --git a/Endpoint/Common/Attributes/NotFoundResponseAttribute.cs b/Endpoint/Common/Attributes/NotFoundResponseAttribute.cs
new file mode 100644
index 0000000..39527ea
--- /dev/null
+++ b/Endpoint/Common/Attributes/NotFoundResponseAttribute.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.Dto.Responses;
+using System;
+
+namespace Mirea.Api.Endpoint.Common.Attributes;
+
+[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
+public class NotFoundResponseAttribute() : ProducesResponseTypeAttribute(typeof(ErrorResponse), StatusCodes.Status404NotFound);
\ No newline at end of file
diff --git a/Endpoint/ConfigureSwaggerOptions.cs b/Endpoint/Configuration/ConfigureSwaggerOptions.cs
similarity index 96%
rename from Endpoint/ConfigureSwaggerOptions.cs
rename to Endpoint/Configuration/ConfigureSwaggerOptions.cs
index 9b53140..39280bb 100644
--- a/Endpoint/ConfigureSwaggerOptions.cs
+++ b/Endpoint/Configuration/ConfigureSwaggerOptions.cs
@@ -5,7 +5,7 @@ using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
-namespace Mirea.Api.Endpoint;
+namespace Mirea.Api.Endpoint.Configuration;
public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions
{
diff --git a/Endpoint/EnvironmentManager.cs b/Endpoint/Configuration/EnvironmentManager.cs
similarity index 93%
rename from Endpoint/EnvironmentManager.cs
rename to Endpoint/Configuration/EnvironmentManager.cs
index 3cbe859..cc2b201 100644
--- a/Endpoint/EnvironmentManager.cs
+++ b/Endpoint/Configuration/EnvironmentManager.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
-namespace Mirea.Api.Endpoint;
+namespace Mirea.Api.Endpoint.Configuration;
internal static class EnvironmentManager
{
diff --git a/Endpoint/SwaggerDefaultValues.cs b/Endpoint/Configuration/SwaggerDefaultValues.cs
similarity index 93%
rename from Endpoint/SwaggerDefaultValues.cs
rename to Endpoint/Configuration/SwaggerDefaultValues.cs
index d47c591..cefb307 100644
--- a/Endpoint/SwaggerDefaultValues.cs
+++ b/Endpoint/Configuration/SwaggerDefaultValues.cs
@@ -6,7 +6,7 @@ using System;
using System.Linq;
using System.Text.Json;
-namespace Mirea.Api.Endpoint;
+namespace Mirea.Api.Endpoint.Configuration;
public class SwaggerDefaultValues : IOperationFilter
{
@@ -38,7 +38,7 @@ public class SwaggerDefaultValues : IOperationFilter
{
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
- parameter.Description ??= description.ModelMetadata?.Description;
+ parameter.Description ??= description.ModelMetadata.Description;
if (parameter.Schema.Default == null &&
description.DefaultValue != null &&
diff --git a/Endpoint/Controllers/BaseController.cs b/Endpoint/Controllers/BaseController.cs
new file mode 100644
index 0000000..82c4c7a
--- /dev/null
+++ b/Endpoint/Controllers/BaseController.cs
@@ -0,0 +1,7 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Mirea.Api.Endpoint.Controllers;
+
+[ApiController]
+[Route("api/[controller]/[action]")]
+public class BaseController : ControllerBase;
\ No newline at end of file
diff --git a/Endpoint/Controllers/V1/BaseControllerV1.cs b/Endpoint/Controllers/V1/BaseControllerV1.cs
new file mode 100644
index 0000000..6ebe1f3
--- /dev/null
+++ b/Endpoint/Controllers/V1/BaseControllerV1.cs
@@ -0,0 +1,8 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Mirea.Api.Endpoint.Controllers.V1;
+
+[ApiVersion("1.0")]
+[Produces("application/json")]
+[Route("api/v{version:apiVersion}/[controller]/[action]")]
+public class BaseControllerV1 : BaseController;
\ No newline at end of file
diff --git a/Endpoint/Controllers/V1/CampusController.cs b/Endpoint/Controllers/V1/CampusController.cs
new file mode 100644
index 0000000..ae83834
--- /dev/null
+++ b/Endpoint/Controllers/V1/CampusController.cs
@@ -0,0 +1,61 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Campus.Queries.GetCampusBasicInfoList;
+using Mirea.Api.DataAccess.Application.Cqrs.Campus.Queries.GetCampusDetails;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1
+{
+ public class CampusController(IMediator mediator) : BaseControllerV1
+ {
+ ///
+ /// Gets basic information about campuses.
+ ///
+ /// Basic information about campuses.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task>> Get()
+ {
+ var result = await mediator.Send(new GetCampusBasicInfoListQuery());
+
+ return Ok(result.Campuses
+ .Select(c => new CampusBasicInfoResponse()
+ {
+ Id = c.Id,
+ CodeName = c.CodeName,
+ FullName = c.FullName
+ })
+ );
+ }
+
+ ///
+ /// Gets details of a specific campus by ID.
+ ///
+ /// Campus ID.
+ /// Details of the specified campus.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetCampusDetailsQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new CampusDetailsResponse()
+ {
+ Id = result.Id,
+ CodeName = result.CodeName,
+ FullName = result.FullName,
+ Address = result.Address
+ });
+ }
+ }
+}
diff --git a/Endpoint/Controllers/V1/DisciplineController.cs b/Endpoint/Controllers/V1/DisciplineController.cs
new file mode 100644
index 0000000..056b208
--- /dev/null
+++ b/Endpoint/Controllers/V1/DisciplineController.cs
@@ -0,0 +1,65 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Discipline.Queries.GetDisciplineDetails;
+using Mirea.Api.DataAccess.Application.Cqrs.Discipline.Queries.GetDisciplineList;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1
+{
+ public class DisciplineController(IMediator mediator) : BaseControllerV1
+ {
+ ///
+ /// Gets a paginated list of disciplines.
+ ///
+ /// Page number. Start from 0.
+ /// Number of items per page.
+ /// Paginated list of disciplines.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ public async Task>> Get([FromQuery] int? page, [FromQuery] int? pageSize)
+ {
+ var result = await mediator.Send(new GetDisciplineListQuery()
+ {
+ Page = page,
+ PageSize = pageSize
+ });
+
+ return Ok(result.Disciplines
+ .Select(d => new DisciplineResponse()
+ {
+ Id = d.Id,
+ Name = d.Name
+ })
+ );
+ }
+
+ ///
+ /// Gets details of a specific discipline by ID.
+ ///
+ /// Discipline ID.
+ /// Details of the specified discipline.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetDisciplineInfoQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new DisciplineResponse()
+ {
+ Id = result.Id,
+ Name = result.Name
+ });
+ }
+ }
+}
diff --git a/Endpoint/Controllers/V1/FacultyController.cs b/Endpoint/Controllers/V1/FacultyController.cs
new file mode 100644
index 0000000..3b4cd61
--- /dev/null
+++ b/Endpoint/Controllers/V1/FacultyController.cs
@@ -0,0 +1,69 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyDetails;
+using Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyList;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1
+{
+ public class FacultyController(IMediator mediator) : BaseControllerV1
+ {
+ ///
+ /// Gets a paginated list of faculties.
+ ///
+ /// Page number. Start from 0.
+ /// Number of items per page.
+ /// Paginated list of faculties.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ public async Task>> Get([FromQuery] int? page, [FromQuery] int? pageSize)
+ {
+ var result = await mediator.Send(new GetFacultyListQuery()
+ {
+ Page = page,
+ PageSize = pageSize
+ });
+
+ return Ok(result.Faculties
+ .Select(f => new FacultyResponse()
+ {
+ Id = f.Id,
+ Name = f.Name,
+ CampusId = f.CampusId
+ })
+ );
+ }
+
+ ///
+ /// Gets details of a specific faculty by ID.
+ ///
+ /// Faculty ID.
+ /// Details of the specified faculty.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetFacultyInfoQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new FacultyDetailsResponse()
+ {
+ Id = result.Id,
+ Name = result.Name,
+ CampusId = result.CampusId,
+ CampusCode = result.CampusCode,
+ CampusName = result.CampusName
+ });
+ }
+ }
+}
diff --git a/Endpoint/Controllers/V1/GroupController.cs b/Endpoint/Controllers/V1/GroupController.cs
new file mode 100644
index 0000000..cead029
--- /dev/null
+++ b/Endpoint/Controllers/V1/GroupController.cs
@@ -0,0 +1,108 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Group.Queries.GetGroupDetails;
+using Mirea.Api.DataAccess.Application.Cqrs.Group.Queries.GetGroupList;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1
+{
+ public class GroupController(IMediator mediator) : BaseControllerV1
+ {
+ private static int GetCourseNumber(string groupName)
+ {
+ var current = DateTime.Now;
+ if (!int.TryParse(groupName[2..], out var yearOfGroup)
+ && !int.TryParse(groupName.Split('-')[^1][..2], out yearOfGroup))
+ return -1;
+
+ // Convert a two-digit year to a four-digit one
+ yearOfGroup += current.Year / 100 * 100;
+
+ return current.Year - yearOfGroup + (current.Month < 9 ? 0 : 1);
+ }
+
+ ///
+ /// Retrieves a list of groups.
+ ///
+ /// The page number for pagination (optional).
+ /// The page size for pagination (optional).
+ /// A list of groups.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ public async Task>> Get([FromQuery] int? page, [FromQuery] int? pageSize)
+ {
+ var result = await mediator.Send(new GetGroupListQuery()
+ {
+ Page = page,
+ PageSize = pageSize
+ });
+
+ return Ok(result.Groups
+ .Select(g => new GroupResponse()
+ {
+ Id = g.Id,
+ Name = g.Name,
+ FacultyId = g.FacultyId,
+ CourseNumber = GetCourseNumber(g.Name)
+ })
+ );
+ }
+
+ ///
+ /// Retrieves detailed information about a specific group.
+ ///
+ /// The ID of the group to retrieve.
+ /// Detailed information about the group.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetGroupInfoQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new GroupDetailsResponse()
+ {
+ Id = result.Id,
+ Name = result.Name,
+ FacultyId = result.FacultyId,
+ FacultyName = result.Faculty,
+ CourseNumber = GetCourseNumber(result.Name)
+ });
+ }
+
+ ///
+ /// Retrieves a list of groups by faculty ID.
+ ///
+ /// The ID of the faculty.
+ /// A list of groups belonging to the specified faculty.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task>> GetByFaculty(int id)
+ {
+ var result = await mediator.Send(new GetGroupListQuery());
+
+ return Ok(result.Groups
+ .Where(g => g.FacultyId == id)
+ .Select(g => new GroupResponse()
+ {
+ Id = g.Id,
+ Name = g.Name,
+ CourseNumber = GetCourseNumber(g.Name),
+ FacultyId = g.FacultyId
+ }));
+ }
+ }
+}
diff --git a/Endpoint/Controllers/V1/LectureHallController.cs b/Endpoint/Controllers/V1/LectureHallController.cs
new file mode 100644
index 0000000..de2f21f
--- /dev/null
+++ b/Endpoint/Controllers/V1/LectureHallController.cs
@@ -0,0 +1,84 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.LectureHall.Queries.GetLectureHallDetails;
+using Mirea.Api.DataAccess.Application.Cqrs.LectureHall.Queries.GetLectureHallList;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1
+{
+ public class LectureHallController(IMediator mediator) : BaseControllerV1
+ {
+ ///
+ /// Retrieves a list of all lecture halls.
+ ///
+ /// A list of lecture halls.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task>> Get()
+ {
+ var result = await mediator.Send(new GetLectureHallListQuery());
+
+ return Ok(result.LectureHalls
+ .Select(l => new LectureHallResponse()
+ {
+ Id = l.Id,
+ Name = l.Name,
+ CampusId = l.CampusId
+ })
+ );
+ }
+
+ ///
+ /// Retrieves details of a specific lecture hall by its ID.
+ ///
+ /// The ID of the lecture hall to retrieve.
+ /// The details of the specified lecture hall.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetLectureHallInfoQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new LectureHallDetailsResponse()
+ {
+ Id = result.Id,
+ Name = result.Name,
+ CampusId = result.CampusId,
+ CampusCode = result.CampusCode,
+ CampusName = result.CampusName
+ });
+ }
+
+ ///
+ /// Retrieves a list of lecture halls by campus ID.
+ ///
+ /// The ID of the campus.
+ /// A list of lecture halls in the specified campus.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task>> GetByCampus(int id)
+ {
+ var result = await mediator.Send(new GetLectureHallListQuery());
+
+ return Ok(result.LectureHalls.Where(l => l.CampusId == id)
+ .Select(l => new LectureHallResponse()
+ {
+ Id = l.Id,
+ Name = l.Name,
+ CampusId = l.CampusId
+ }));
+ }
+ }
+}
diff --git a/Endpoint/Controllers/V1/ProfessorController.cs b/Endpoint/Controllers/V1/ProfessorController.cs
new file mode 100644
index 0000000..5a9053a
--- /dev/null
+++ b/Endpoint/Controllers/V1/ProfessorController.cs
@@ -0,0 +1,66 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Professor.Queries.GetProfessorDetails;
+using Mirea.Api.DataAccess.Application.Cqrs.Professor.Queries.GetProfessorList;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1;
+
+public class ProfessorController(IMediator mediator) : BaseControllerV1
+{
+ ///
+ /// Retrieves a list of professors.
+ ///
+ /// The page number for pagination (optional).
+ /// The page size for pagination (optional).
+ /// A list of professors.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ public async Task>> Get([FromQuery] int? page, [FromQuery] int? pageSize)
+ {
+ var result = await mediator.Send(new GetProfessorListQuery()
+ {
+ Page = page,
+ PageSize = pageSize
+ });
+
+ return Ok(result.Professors
+ .Select(p => new ProfessorResponse()
+ {
+ Id = p.Id,
+ Name = p.Name,
+ AltName = p.AltName
+ })
+ );
+ }
+
+ ///
+ /// Retrieves detailed information about a specific professor.
+ ///
+ /// The ID of the professor to retrieve.
+ /// Detailed information about the professor.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetDetails(int id)
+ {
+ var result = await mediator.Send(new GetProfessorInfoQuery()
+ {
+ Id = id
+ });
+
+ return Ok(new ProfessorResponse()
+ {
+ Id = result.Id,
+ Name = result.Name,
+ AltName = result.AltName
+ });
+ }
+}
\ No newline at end of file
diff --git a/Endpoint/Controllers/V1/ScheduleController.cs b/Endpoint/Controllers/V1/ScheduleController.cs
new file mode 100644
index 0000000..43b47ad
--- /dev/null
+++ b/Endpoint/Controllers/V1/ScheduleController.cs
@@ -0,0 +1,304 @@
+using MediatR;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
+using Mirea.Api.Dto.Requests;
+using Mirea.Api.Dto.Responses;
+using Mirea.Api.Dto.Responses.Schedule;
+using Mirea.Api.Endpoint.Common.Attributes;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Mirea.Api.Endpoint.Controllers.V1;
+
+public class ScheduleController(IMediator mediator) : BaseControllerV1
+{
+ ///
+ /// Retrieves schedules based on various filters.
+ ///
+ /// The request object containing filter criteria.
+ /// A list of schedules matching the filter criteria.
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task>> Get([FromBody] ScheduleRequest request)
+
+ {
+ if ((request.Groups == null || !request.Groups.Any()) &&
+ (request.Disciplines == null || !request.Disciplines.Any()) &&
+ (request.Professors == null || !request.Professors.Any()) &&
+ (request.LectureHalls == null || !request.LectureHalls.Any()))
+ {
+ return BadRequest(new ErrorResponse()
+ {
+ Error = "At least one of the arguments must be selected."
+ + (request.IsEven.HasValue
+ ? $" \"{nameof(request.IsEven)}\" is not a strong argument"
+ : string.Empty),
+ Code = StatusCodes.Status400BadRequest
+ });
+ }
+
+ var result = (await mediator.Send(new GetScheduleListQuery()
+ {
+ IsEven = request.IsEven,
+ DisciplineIds = request.Disciplines,
+ GroupIds = request.Groups,
+ LectureHallIds = request.LectureHalls,
+ ProfessorIds = request.Professors
+ })).Schedules;
+
+ if (result.Count == 0) NoContent();
+
+ return Ok(result.Select(s => new ScheduleResponse()
+ {
+ DayOfWeek = s.DayOfWeek,
+ PairNumber = s.PairNumber,
+ IsEven = s.IsEven,
+ Discipline = s.Discipline,
+ DisciplineId = s.DisciplineId,
+ TypeOfOccupation = s.TypeOfOccupation,
+ Group = s.Group,
+ GroupId = s.GroupId,
+ LectureHalls = s.LectureHalls,
+ LectureHallsId = s.LectureHallsId,
+ Professors = s.Professors,
+ ProfessorsId = s.ProfessorsId,
+ Campus = s.Campus,
+ CampusId = s.CampusId,
+ LinkToMeet = s.LinkToMeet
+ }));
+
+ }
+
+ ///
+ /// Retrieves schedules for a specific group based on various filters.
+ ///
+ /// The ID of the group.
+ /// A value indicating whether to retrieve schedules for even weeks.
+ /// An array of discipline IDs.
+ /// An array of professor IDs.
+ /// An array of lecture hall IDs.
+ /// A response containing schedules for the specified group.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetByGroup(int id,
+ [FromQuery] bool? isEven = null,
+ [FromQuery] int[]? disciplines = null,
+ [FromQuery] int[]? professors = null,
+ [FromQuery] int[]? lectureHalls = null)
+
+ {
+ var result = (await mediator.Send(new GetScheduleListQuery()
+ {
+ IsEven = isEven,
+ DisciplineIds = disciplines,
+ GroupIds = [id],
+ LectureHallIds = lectureHalls,
+ ProfessorIds = professors
+ })).Schedules;
+
+ if (result.Count == 0) NoContent();
+
+ return Ok(new GroupScheduleResponse()
+ {
+ Group = result[0].Group,
+ GroupId = result[0].GroupId,
+ Schedules = result.Select(g => new GroupScheduleInfo()
+ {
+ DayOfWeek = g.DayOfWeek,
+ PairNumber = g.PairNumber,
+ IsEven = g.IsEven,
+ Discipline = g.Discipline,
+ DisciplineId = g.DisciplineId,
+ TypeOfOccupation = g.TypeOfOccupation,
+ LectureHalls = g.LectureHalls,
+ LectureHallsId = g.LectureHallsId,
+ Professors = g.Professors,
+ ProfessorsId = g.ProfessorsId,
+ Campus = g.Campus,
+ CampusId = g.CampusId,
+ LinkToMeet = g.LinkToMeet
+ })
+ });
+ }
+
+ ///
+ /// Retrieves schedules for a specific professor based on various filters.
+ ///
+ /// The ID of the professor.
+ /// A value indicating whether to retrieve schedules for even weeks.
+ /// An array of discipline IDs.
+ /// An array of group IDs.
+ /// An array of lecture hall IDs.
+ /// A response containing schedules for the specified professor.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetByProfessor(int id,
+ [FromQuery] bool? isEven = null,
+ [FromQuery] int[]? disciplines = null,
+ [FromQuery] int[]? groups = null,
+ [FromQuery] int[]? lectureHalls = null)
+
+ {
+ var result = (await mediator.Send(new GetScheduleListQuery()
+ {
+ IsEven = isEven,
+ DisciplineIds = disciplines,
+ GroupIds = groups,
+ LectureHallIds = lectureHalls,
+ ProfessorIds = [id]
+ })).Schedules;
+
+ if (result.Count == 0) NoContent();
+
+ return Ok(new ProfessorScheduleResponse()
+ {
+ Professor = result.Select(professor =>
+ professor.Professors.FirstOrDefault(x => !string.IsNullOrEmpty(x))
+ ).First()!,
+ ProfessorId = result.Select(professor =>
+ professor.ProfessorsId.FirstOrDefault(x => x != null)
+ ).First()!.Value,
+ Schedules = result.Select(p => new ProfessorScheduleInfo()
+ {
+ DayOfWeek = p.DayOfWeek,
+ PairNumber = p.PairNumber,
+ IsEven = p.IsEven,
+ Discipline = p.Discipline,
+ DisciplineId = p.DisciplineId,
+ TypeOfOccupation = p.TypeOfOccupation,
+ Group = p.Group,
+ GroupId = p.GroupId,
+ LectureHalls = p.LectureHalls,
+ LectureHallsId = p.LectureHallsId,
+ Campus = p.Campus,
+ CampusId = p.CampusId,
+ LinkToMeet = p.LinkToMeet
+ })
+ });
+ }
+
+ ///
+ /// Retrieves schedules for a specific lecture hall based on various filters.
+ ///
+ /// The ID of the lecture hall.
+ /// A value indicating whether to retrieve schedules for even weeks.
+ /// An array of discipline IDs.
+ /// An array of professor IDs.
+ /// An array of group IDs.
+ /// A response containing schedules for the specified lecture hall.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetByLectureHall(int id,
+ [FromQuery] bool? isEven = null,
+ [FromQuery] int[]? disciplines = null,
+ [FromQuery] int[]? groups = null,
+ [FromQuery] int[]? professors = null)
+
+ {
+ var result = (await mediator.Send(new GetScheduleListQuery()
+ {
+ IsEven = isEven,
+ DisciplineIds = disciplines,
+ GroupIds = groups,
+ LectureHallIds = [id],
+ ProfessorIds = professors
+ })).Schedules;
+
+ if (result.Count == 0) NoContent();
+
+ return Ok(new LectureHallScheduleResponse()
+ {
+ LectureHalls = result.Select(lectureHall =>
+ lectureHall.LectureHalls.FirstOrDefault(x => !string.IsNullOrEmpty(x))
+ ).First()!,
+ LectureHallsId = result.Select(lectureHall =>
+ lectureHall.LectureHallsId.FirstOrDefault(x => x != null)
+ ).First()!.Value,
+ Schedules = result.Select(l => new LectureHallScheduleInfo()
+ {
+ DayOfWeek = l.DayOfWeek,
+ PairNumber = l.PairNumber,
+ IsEven = l.IsEven,
+ Discipline = l.Discipline,
+ DisciplineId = l.DisciplineId,
+ TypeOfOccupation = l.TypeOfOccupation,
+ Group = l.Group,
+ GroupId = l.GroupId,
+ Professors = l.Professors,
+ ProfessorsId = l.ProfessorsId,
+ Campus = l.Campus,
+ CampusId = l.CampusId,
+ LinkToMeet = l.LinkToMeet
+ })
+ });
+ }
+
+ ///
+ /// Retrieves schedules for a specific discipline based on various filters.
+ ///
+ /// The ID of the discipline.
+ /// A value indicating whether to retrieve schedules for even weeks.
+ /// An array of group IDs.
+ /// An array of professor IDs.
+ /// An array of lecture hall IDs.
+ /// A response containing schedules for the specified discipline.
+ [HttpGet("{id:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [BadRequestResponse]
+ [NotFoundResponse]
+ public async Task> GetByDiscipline(int id,
+ [FromQuery] bool? isEven = null,
+ [FromQuery] int[]? groups = null,
+ [FromQuery] int[]? professors = null,
+ [FromQuery] int[]? lectureHalls = null)
+
+ {
+ var result = (await mediator.Send(new GetScheduleListQuery()
+ {
+ IsEven = isEven,
+ DisciplineIds = [id],
+ GroupIds = groups,
+ LectureHallIds = [id],
+ ProfessorIds = professors
+ })).Schedules;
+
+ if (result.Count == 0) NoContent();
+
+ return Ok(new DisciplineScheduleResponse()
+ {
+ Discipline = result[0].Discipline,
+ DisciplineId = result[0].DisciplineId,
+ Schedules = result.Select(d => new DisciplineScheduleInfo()
+ {
+ DayOfWeek = d.DayOfWeek,
+ PairNumber = d.PairNumber,
+ IsEven = d.IsEven,
+ TypeOfOccupation = d.TypeOfOccupation,
+ Group = d.Group,
+ GroupId = d.GroupId,
+ LectureHalls = d.LectureHalls,
+ LectureHallsId = d.LectureHallsId,
+ Professors = d.Professors,
+ ProfessorsId = d.ProfessorsId,
+ Campus = d.Campus,
+ CampusId = d.CampusId,
+ LinkToMeet = d.LinkToMeet
+ })
+ });
+ }
+}
\ No newline at end of file
diff --git a/Endpoint/Endpoint.csproj b/Endpoint/Endpoint.csproj
index 84dcfc2..0191a2e 100644
--- a/Endpoint/Endpoint.csproj
+++ b/Endpoint/Endpoint.csproj
@@ -28,6 +28,7 @@
+
diff --git a/Endpoint/Program.cs b/Endpoint/Program.cs
index 920ce15..3607500 100644
--- a/Endpoint/Program.cs
+++ b/Endpoint/Program.cs
@@ -8,6 +8,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Mirea.Api.DataAccess.Application;
using Mirea.Api.DataAccess.Persistence;
+using Mirea.Api.Endpoint.Configuration;
using Mirea.Api.Endpoint.Properties;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;