Compare commits

..

26 Commits

Author SHA1 Message Date
aa58e0817d stop producting 2025-05-20 17:39:20 +03:00
0cedc4a00a fix 2025-05-20 00:13:23 +03:00
02bf7c34ef db 2025-05-19 23:02:29 +03:00
b1c96467cc dbcreate 2025-05-19 22:59:55 +03:00
ed481a5e62 fix 2025-05-18 23:10:16 +04:00
cee5905b67 not work edit 2025-05-18 11:32:29 +03:00
bf4e4a0d18 Merge branch 'WebStep7' of https://git.is.ulstu.ru/Dmitriev.An/CourseWork_ISEbd21_UniversityAllExpelled into WebStep7 2025-05-17 22:31:12 +03:00
9eb709a3ee fix 2025-05-17 22:30:49 +03:00
7ad22682fb win 2025-05-17 22:30:26 +03:00
011151dba0 mainLK.html/createStudentTraining.html/edu-create.css/createEdules 2025-05-17 20:00:43 +04:00
786f9ef7b1 fix 2025-05-17 18:46:19 +03:00
3620b7fe99 biggestWorkk 2025-05-17 18:46:02 +03:00
8b976b7523 big work complited. DataBase created And more fix 2025-05-17 17:36:31 +03:00
bb76ebcd83 html js and css. plus infrastructure in web db 2025-05-17 16:03:12 +03:00
33e2641318 Merge branch 'WebStep7' of https://git.is.ulstu.ru/Dmitriev.An/CourseWork_DmitrievA.A_ISEbd21_UniversityAllExpelled into WebStep7 2025-05-17 12:53:08 +04:00
b406dea953 Merge branch 'WebStep7Teacher' into WebStep7_Student 2025-05-17 12:47:28 +03:00
7b678ef445 lk, payment 1st path, reprts 2025-05-17 12:39:20 +03:00
4d44610c2f change 2025-05-17 12:52:59 +04:00
3fcaec39e9 logo + teacherlk 2025-05-17 12:37:24 +04:00
b554fcc2f3 index + registr 2025-05-16 19:59:28 +03:00
3facbf9d28 Project WebApi Created 2025-05-16 16:19:45 +03:00
443b29e70b fix 2025-05-16 16:15:34 +04:00
141d39b42e fix reqest 2025-04-27 11:42:49 +03:00
69392019bb Merge branch 'RealizationBusinessLogicContractClient' into MainRealizationBusinessLogicContract 2025-04-27 11:37:23 +03:00
2c62e282f9 fix 2025-04-27 11:33:25 +03:00
245cb9e87e Realization BusinessLogic 2025-04-27 11:40:00 +04:00
85 changed files with 4577 additions and 725 deletions

View File

@@ -5,12 +5,12 @@ VisualStudioVersion = 17.13.35806.99
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversityAllExpelled_Models", "UniversityAllExpelled_Models\UniversityAllExpelled_Models.csproj", "{B2364D1E-38B8-4DF7-90DB-49F8463A1B40}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversityAllExpelled_Tests", "UniversityAllExpelled_Tests\UniversityAllExpelled_Tests.csproj", "{E3D5BB9F-436E-44FC-AB2C-5D643628BAD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversityAllExpelled_DataBase", "UniversityAllExpelled_DataBase\UniversityAllExpelled_DataBase.csproj", "{23807279-75F8-4BEC-831B-24AA27ABA57A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversityAllExpelled_BusinessLogic", "UniversityAllExpelled_BusinessLogic\UniversityAllExpelled_BusinessLogic.csproj", "{6C4551E0-879E-4D28-9C2A-019929E0211A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversityAllExpelled_WebApi", "UniversityAllExpelled_WebApi\UniversityAllExpelled_WebApi.csproj", "{F2CB59D0-8BC0-477E-8BC6-5A230AE04694}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,10 +21,6 @@ Global
{B2364D1E-38B8-4DF7-90DB-49F8463A1B40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2364D1E-38B8-4DF7-90DB-49F8463A1B40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2364D1E-38B8-4DF7-90DB-49F8463A1B40}.Release|Any CPU.Build.0 = Release|Any CPU
{E3D5BB9F-436E-44FC-AB2C-5D643628BAD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3D5BB9F-436E-44FC-AB2C-5D643628BAD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3D5BB9F-436E-44FC-AB2C-5D643628BAD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3D5BB9F-436E-44FC-AB2C-5D643628BAD2}.Release|Any CPU.Build.0 = Release|Any CPU
{23807279-75F8-4BEC-831B-24AA27ABA57A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23807279-75F8-4BEC-831B-24AA27ABA57A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23807279-75F8-4BEC-831B-24AA27ABA57A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -33,6 +29,10 @@ Global
{6C4551E0-879E-4D28-9C2A-019929E0211A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C4551E0-879E-4D28-9C2A-019929E0211A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C4551E0-879E-4D28-9C2A-019929E0211A}.Release|Any CPU.Build.0 = Release|Any CPU
{F2CB59D0-8BC0-477E-8BC6-5A230AE04694}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2CB59D0-8BC0-477E-8BC6-5A230AE04694}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2CB59D0-8BC0-477E-8BC6-5A230AE04694}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2CB59D0-8BC0-477E-8BC6-5A230AE04694}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,163 @@
using Microsoft.Extensions.Logging;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels;
using UniversityAllExpelled_Models.Extensions;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.StorageContracts;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Data;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class EducationBusinessLogicContract(IEducationStorageContract educationStorageContract, ILogger<EducationBusinessLogicContract> logger)
: IEducationBusinessLogicContract
{
private readonly IEducationStorageContract _educationStorageContract = educationStorageContract;
private readonly ILogger _logger = logger;
public List<EducationDataModel> GetAllEducations()
{
_logger.LogInformation("GetAllEducations");
return _educationStorageContract.GetList() ?? throw new NullListException();
}
public List<EducationDataModel> GetAllEducationsByActive(bool isActive)
{
_logger.LogInformation("GetAllEducationsByActive with isActive = {isActive}", isActive);
return _educationStorageContract.GetListByActive(isActive) ?? throw new NullListException();
}
public EducationDataModel? GetEducationById(string educationId)
{
_logger.LogInformation("GetEducationById: {educationId}", educationId);
if (string.IsNullOrEmpty(educationId))
{
throw new ArgumentNullException(nameof(educationId));
}
if (!Guid.TryParse(educationId, out _))
{
throw new ValidationException("Education ID must be in valid GUID format");
}
return _educationStorageContract.GetElementById(educationId);
}
public EducationDataModel? GetEducationByIdByActive(string educationId, bool isActive)
{
_logger.LogInformation("GetEducationByIdByActive: {educationId} with isActive = {isActive}", educationId, isActive);
var education = GetEducationById(educationId);
return education != null && education.Active == isActive ? education : null;
}
public List<EducationDataModel> GetAllEducationsByPeriod(DateTime startDate, DateTime endDate)
{
_logger.LogInformation("GetAllEducationsByPeriod from {startDate} to {endDate}", startDate, endDate);
if (startDate > endDate)
{
throw new IncorrectDatesException(startDate, endDate);
}
return _educationStorageContract.GetListByDateRange(startDate, endDate) ?? throw new NullListException();
}
public List<EducationDataModel> GetAllEducationsByTeacher(string teacherId)
{
_logger.LogInformation("GetAllEducationsByTeacher: {teacherId}", teacherId);
if (string.IsNullOrEmpty(teacherId))
{
throw new ArgumentNullException(nameof(teacherId));
}
if (!Guid.TryParse(teacherId, out _))
{
throw new ValidationException("Teacher ID must be in valid GUID format");
}
return _educationStorageContract.GetListByTeacherId(teacherId) ?? throw new NullListException();
}
public List<EducationDataModel> GetAllEducationsByTeacherByActive(string teacherId, bool isActive)
{
_logger.LogInformation("GetAllEducationsByTeacherByActive: {teacherId} with isActive = {isActive}", teacherId, isActive);
var educations = GetAllEducationsByTeacher(teacherId);
return educations.Where(e => e.Active == isActive).ToList();
}
public List<EducationDataModel> GetAllEducationsByTeacherByPeriod(string teacherId, DateTime startDate, DateTime endDate)
{
_logger.LogInformation(
"GetAllEducationsByTeacherByPeriod: {teacherId} from {startDate} to {endDate}",
teacherId, startDate, endDate);
var educations = GetAllEducationsByTeacher(teacherId);
return educations.Where(e => e.StartDate >= startDate && e.EndDate <= endDate).ToList();
}
public List<EducationDataModel> GetAllEducationsByTeacherByPeriodByActive(string teacherId, DateTime startDate, DateTime endDate, bool isActive)
{
_logger.LogInformation(
"GetAllEducationsByTeacherByPeriodByActive: {teacherId} from {startDate} to {endDate} with isActive = {isActive}",
teacherId, startDate, endDate, isActive);
var educations = GetAllEducationsByTeacher(teacherId);
return educations.Where(e =>
e.Active == isActive &&
e.StartDate >= startDate &&
e.EndDate <= endDate).ToList();
}
public void CreateEducation(EducationDataModel educationDataModel)
{
_logger.LogInformation("CreateEducation: {json}", JsonSerializer.Serialize(educationDataModel));
ArgumentNullException.ThrowIfNull(educationDataModel);
educationDataModel.Validate();
var existingEducation = _educationStorageContract.GetElementById(educationDataModel.Id);
if (existingEducation != null)
{
throw new ElementExistsException("Id", educationDataModel.Id);
}
_educationStorageContract.AddElement(educationDataModel);
}
public void UpdateEducation(EducationDataModel educationDataModel)
{
_logger.LogInformation("UpdateEducation: {json}", JsonSerializer.Serialize(educationDataModel));
ArgumentNullException.ThrowIfNull(educationDataModel);
educationDataModel.Validate();
var existingEducation = _educationStorageContract.GetElementById(educationDataModel.Id);
if (existingEducation == null)
{
throw new ElementNotFoundException(educationDataModel.Id);
}
_educationStorageContract.UpdElement(educationDataModel);
}
public void RestoreEducation(string id)
{
_logger.LogInformation("RestoreEducation: {id}", id);
var education = GetEducationById(id) ?? throw new ElementNotFoundException(id);
education.Active = true;
_educationStorageContract.UpdElement(education);
}
public void DeleteEducation(string id)
{
_logger.LogInformation("DeleteEducation: {id}", id);
var education = GetEducationById(id) ?? throw new ElementNotFoundException(id);
education.Active = false;
_educationStorageContract.UpdElement(education);
}
}

View File

@@ -0,0 +1,154 @@
using Microsoft.Extensions.Logging;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels.Worker;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.StorageContracts;
using System.Text.Json;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class EducationLessonsBusinessLogicContract(
IEducationLessonsStorageContract storageContract,
ILogger<EducationLessonsBusinessLogicContract> logger)
: IEducationLessonsBusinessLogicContract
{
private readonly IEducationLessonsStorageContract _storage = storageContract;
private readonly ILogger _logger = logger;
public List<EducationLessonsDataModel> GetAllEducationLessons()
{
_logger.LogInformation("Getting all education-lessons connections");
return _storage.GetList() ?? throw new NullListException();
}
public EducationLessonsDataModel? GetEducationLesson(string educationId, string lessonId)
{
_logger.LogInformation("Getting education-lesson connection for EducationId: {educationId}, LessonId: {lessonId}",
educationId, lessonId);
ValidateIds(educationId, lessonId);
return _storage.GetElementByIds(educationId, lessonId);
}
public List<EducationLessonsDataModel> GetLessonsByEducation(string educationId)
{
_logger.LogInformation("Getting all lessons for education: {educationId}", educationId);
ValidateId(educationId, "Education ID");
return _storage.GetListByEducationId(educationId) ?? throw new NullListException();
}
public List<string> GetLessonIdsByEducation(string educationId)
{
_logger.LogInformation("Getting lesson IDs for education: {educationId}", educationId);
return GetLessonsByEducation(educationId).Select(x => x.LessonsId).ToList();
}
public List<EducationLessonsDataModel> GetEducationsByLesson(string lessonId)
{
_logger.LogInformation("Getting all educations for lesson: {lessonId}", lessonId);
ValidateId(lessonId, "Lesson ID");
return _storage.GetListByLessonId(lessonId) ?? throw new NullListException();
}
public List<string> GetEducationIdsByLesson(string lessonId)
{
_logger.LogInformation("Getting education IDs for lesson: {lessonId}", lessonId);
return GetEducationsByLesson(lessonId).Select(x => x.EducationId).ToList();
}
public void CreateEducationLesson(EducationLessonsDataModel educationLesson)
{
_logger.LogInformation("Creating new education-lesson connection: {data}",
JsonSerializer.Serialize(educationLesson));
ArgumentNullException.ThrowIfNull(educationLesson);
educationLesson.Validate();
if (_storage.GetElementByIds(educationLesson.EducationId, educationLesson.LessonsId) != null)
{
throw new ElementExistsException("Education-Lesson connection",
$"{educationLesson.EducationId}-{educationLesson.LessonsId}");
}
_storage.AddElement(educationLesson);
}
public void DeleteEducationLesson(string educationId, string lessonId)
{
_logger.LogInformation("Deleting education-lesson connection: EducationId: {educationId}, LessonId: {lessonId}",
educationId, lessonId);
ValidateIds(educationId, lessonId);
var connection = GetEducationLesson(educationId, lessonId) ??
throw new ElementNotFoundException($"Education-Lesson connection {educationId}-{lessonId}");
_storage.DelElement(connection);
}
public void DeleteAllLessonsForEducation(string educationId)
{
_logger.LogInformation("Deleting all lessons for education: {educationId}", educationId);
ValidateId(educationId, "Education ID");
_storage.DelElementsByEducationId(educationId);
}
public void DeleteAllEducationsForLesson(string lessonId)
{
_logger.LogInformation("Deleting all educations for lesson: {lessonId}", lessonId);
ValidateId(lessonId, "Lesson ID");
_storage.DelElementsByLessonId(lessonId);
}
public void AddMultipleLessonsToEducation(string educationId, IEnumerable<string> lessonIds)
{
_logger.LogInformation("Adding multiple lessons to education: {educationId}", educationId);
ValidateId(educationId, "Education ID");
foreach (var lessonId in lessonIds ?? Enumerable.Empty<string>())
{
try
{
CreateEducationLesson(new EducationLessonsDataModel(educationId, lessonId));
}
catch (ElementExistsException)
{
_logger.LogWarning("Connection already exists for EducationId: {educationId}, LessonId: {lessonId}",
educationId, lessonId);
}
}
}
public void RemoveMultipleLessonsFromEducation(string educationId, IEnumerable<string> lessonIds)
{
_logger.LogInformation("Removing multiple lessons from education: {educationId}", educationId);
ValidateId(educationId, "Education ID");
foreach (var lessonId in lessonIds ?? Enumerable.Empty<string>())
{
try
{
DeleteEducationLesson(educationId, lessonId);
}
catch (ElementNotFoundException)
{
_logger.LogWarning("Connection not found for EducationId: {educationId}, LessonId: {lessonId}",
educationId, lessonId);
}
}
}
private void ValidateId(string id, string paramName)
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(paramName);
if (!Guid.TryParse(id, out _))
throw new ValidationException($"{paramName} must be in valid GUID format");
}
private void ValidateIds(string educationId, string lessonId)
{
ValidateId(educationId, "Education ID");
ValidateId(lessonId, "Lesson ID");
}
}

View File

@@ -9,10 +9,10 @@ using System.Text.Json;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class LessonBusinessLogicContract(ILessonStorageContract lessonStorageContract, ILogger logger) : ILessonBusinessLogicContract
internal class LessonBusinessLogicContract(ILessonStorageContract lessonStorageContract, ILogger<LessonBusinessLogicContract> logger) : ILessonBusinessLogicContract
{
private readonly ILessonStorageContract _lessonStorageContract = lessonStorageContract;
private readonly ILogger _logger = logger;
private readonly ILogger<LessonBusinessLogicContract> _logger;
public List<LessonDataModel> GetAllLesson()
{

View File

@@ -12,11 +12,11 @@ namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class PaymentBusinessLogicContract : IPaymentBusinessLogicContract
{
private readonly IPaymentStorageContract _paymentStorage;
private readonly ILogger _logger;
private readonly ILogger<PaymentBusinessLogicContract> _logger;
public PaymentBusinessLogicContract(
IPaymentStorageContract paymentStorage,
ILogger logger)
ILogger<PaymentBusinessLogicContract> logger)
{
_paymentStorage = paymentStorage ?? throw new ArgumentNullException(nameof(paymentStorage));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));

View File

@@ -0,0 +1,224 @@
using Microsoft.Extensions.Logging;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels.Worker;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.StorageContracts;
using System.Text.Json;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class SalaryBusinessLogicContract(
ISalaryStorageContract storageContract,
ILogger<SalaryBusinessLogicContract> logger)
: ISalaryBusinessLogicContract
{
private readonly ISalaryStorageContract _storage = storageContract;
private readonly ILogger _logger = logger;
public List<SalaryDataModel> GetAllSalaries()
{
_logger.LogInformation("Getting all salaries");
return _storage.GetList() ?? throw new NullListException();
}
public SalaryDataModel? GetSalaryById(string salaryId)
{
_logger.LogInformation("Getting salary by ID: {salaryId}", salaryId);
ValidateId(salaryId, "Salary ID");
return _storage.GetElementById(salaryId);
}
public List<SalaryDataModel> GetSalariesByTeacher(string teacherId)
{
_logger.LogInformation("Getting salaries for teacher: {teacherId}", teacherId);
ValidateId(teacherId, "Teacher ID");
return _storage.GetListByTeacherId(teacherId) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesByDate(DateTime date)
{
_logger.LogInformation("Getting salaries for date: {date}", date.ToShortDateString());
return _storage.GetListByDate(date) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesByDateAndTeacher(DateTime date, string teacherId)
{
_logger.LogInformation("Getting salaries for date {date} and teacher {teacherId}",
date.ToShortDateString(), teacherId);
ValidateId(teacherId, "Teacher ID");
return _storage.GetListByDateAndTeacherId(date, teacherId) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesByDateRange(DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Getting salaries from {startDate} to {endDate}",
startDate.ToShortDateString(), endDate.ToShortDateString());
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
return _storage.GetListByDateRange(startDate, endDate) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesByDateRangeAndTeacher(DateTime startDate, DateTime endDate, string teacherId)
{
_logger.LogInformation("Getting salaries from {startDate} to {endDate} for teacher {teacherId}",
startDate.ToShortDateString(), endDate.ToShortDateString(), teacherId);
ValidateId(teacherId, "Teacher ID");
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
return _storage.GetListByDateRangeAndTeacherId(startDate, endDate, teacherId) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesAboveAmount(double amount)
{
_logger.LogInformation("Getting salaries above amount: {amount}", amount);
ValidateAmount(amount);
return _storage.GetListByAmountRange(amount, double.MaxValue) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesAboveAmountForTeacher(double amount, string teacherId)
{
_logger.LogInformation("Getting salaries above amount {amount} for teacher {teacherId}", amount, teacherId);
ValidateAmount(amount);
ValidateId(teacherId, "Teacher ID");
return _storage.GetListByAmountRangeAndTeacherId(amount, double.MaxValue, teacherId) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesBelowAmount(double amount)
{
_logger.LogInformation("Getting salaries below amount: {amount}", amount);
ValidateAmount(amount);
return _storage.GetListByAmountRange(0, amount) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesBelowAmountForTeacher(double amount, string teacherId)
{
_logger.LogInformation("Getting salaries below amount {amount} for teacher {teacherId}", amount, teacherId);
ValidateAmount(amount);
ValidateId(teacherId, "Teacher ID");
return _storage.GetListByAmountRangeAndTeacherId(0, amount, teacherId) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesInAmountRange(double minAmount, double maxAmount)
{
_logger.LogInformation("Getting salaries in range {minAmount}-{maxAmount}", minAmount, maxAmount);
ValidateAmountRange(minAmount, maxAmount);
return _storage.GetListByAmountRange(minAmount, maxAmount) ?? throw new NullListException();
}
public List<SalaryDataModel> GetSalariesInAmountRangeForTeacher(double minAmount, double maxAmount, string teacherId)
{
_logger.LogInformation("Getting salaries in range {minAmount}-{maxAmount} for teacher {teacherId}",
minAmount, maxAmount, teacherId);
ValidateAmountRange(minAmount, maxAmount);
ValidateId(teacherId, "Teacher ID");
return _storage.GetListByAmountRangeAndTeacherId(minAmount, maxAmount, teacherId) ?? throw new NullListException();
}
public void CreateSalary(SalaryDataModel salaryDataModel)
{
_logger.LogInformation("Creating new salary: {data}", JsonSerializer.Serialize(salaryDataModel));
ArgumentNullException.ThrowIfNull(salaryDataModel);
salaryDataModel.Validate();
if (_storage.GetElementById(salaryDataModel.Id) != null)
{
throw new ElementExistsException("Salary", salaryDataModel.Id);
}
_storage.AddElement(salaryDataModel);
}
public void UpdateSalary(SalaryDataModel salaryDataModel)
{
_logger.LogInformation("Updating salary: {data}", JsonSerializer.Serialize(salaryDataModel));
ArgumentNullException.ThrowIfNull(salaryDataModel);
salaryDataModel.Validate();
var existingSalary = _storage.GetElementById(salaryDataModel.Id) ??
throw new ElementNotFoundException(salaryDataModel.Id);
_storage.UpdElement(salaryDataModel);
}
public void DeleteSalary(string id)
{
_logger.LogInformation("Deleting salary with ID: {id}", id);
ValidateId(id, "Salary ID");
var salary = _storage.GetElementById(id) ?? throw new ElementNotFoundException(id);
_storage.DelElement(salary);
}
public double CalculateTotalSalariesForPeriod(DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Calculating total salaries from {startDate} to {endDate}",
startDate.ToShortDateString(), endDate.ToShortDateString());
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
var salaries = GetSalariesByDateRange(startDate, endDate);
return salaries.Sum(s => s.Count);
}
public double CalculateTotalSalariesForTeacherAndPeriod(string teacherId, DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Calculating total salaries for teacher {teacherId} from {startDate} to {endDate}",
teacherId, startDate.ToShortDateString(), endDate.ToShortDateString());
ValidateId(teacherId, "Teacher ID");
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
var salaries = GetSalariesByDateRangeAndTeacher(startDate, endDate, teacherId);
return salaries.Sum(s => s.Count);
}
public double CalculateAverageSalaryForPeriod(DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Calculating average salary from {startDate} to {endDate}",
startDate.ToShortDateString(), endDate.ToShortDateString());
var salaries = GetSalariesByDateRange(startDate, endDate);
return salaries.Any() ? salaries.Average(s => s.Count) : 0;
}
public double CalculateAverageSalaryForTeacherAndPeriod(string teacherId, DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Calculating average salary for teacher {teacherId} from {startDate} to {endDate}",
teacherId, startDate.ToShortDateString(), endDate.ToShortDateString());
var salaries = GetSalariesByDateRangeAndTeacher(startDate, endDate, teacherId);
return salaries.Any() ? salaries.Average(s => s.Count) : 0;
}
private void ValidateId(string id, string paramName)
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(paramName);
if (!Guid.TryParse(id, out _))
throw new ValidationException($"{paramName} must be in valid GUID format");
}
private void ValidateAmount(double amount)
{
if (amount <= 0)
throw new ValidationException("Amount must be greater than zero");
}
private void ValidateAmountRange(double minAmount, double maxAmount)
{
if (minAmount <= 0 || maxAmount <= 0)
throw new ValidationException("Amount values must be greater than zero");
if (minAmount > maxAmount)
throw new ValidationException("Min amount cannot be greater than max amount");
}
}

View File

@@ -15,12 +15,12 @@ internal class StudentBusinessLogicContract : IStudentBusinessLogicContract
{
private readonly IStudentStorageContract _studentStorage;
private readonly IUserStorageContract _userStorage;
private readonly ILogger _logger;
private readonly ILogger<StudentBusinessLogicContract> _logger;
public StudentBusinessLogicContract(
IStudentStorageContract studentStorage,
IUserStorageContract userStorage,
ILogger logger)
ILogger<StudentBusinessLogicContract> logger)
{
_studentStorage = studentStorage ?? throw new ArgumentNullException(nameof(studentStorage));
_userStorage = userStorage ?? throw new ArgumentNullException(nameof(userStorage));

View File

@@ -0,0 +1,175 @@
using Microsoft.Extensions.Logging;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels.Worker;
using UniversityAllExpelled_Models.Enums;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.StorageContracts;
using System.Text.Json;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class TeacherBusinessLogicContract(
ITeacherStorageContract storageContract,
ILogger<TeacherBusinessLogicContract> logger)
: ITeacherBusinessLogicContract
{
private readonly ITeacherStorageContract _storage = storageContract;
private readonly ILogger<TeacherBusinessLogicContract> _logger;
public void CreateTeacher(TeacherDataModel teacherDataModel)
{
_logger.LogInformation("Creating new teacher: {data}", JsonSerializer.Serialize(teacherDataModel));
ArgumentNullException.ThrowIfNull(teacherDataModel);
teacherDataModel.Validate();
if (_storage.GetElementById(teacherDataModel.Id) != null)
throw new ElementExistsException("Teacher", teacherDataModel.Id);
_storage.AddElement(teacherDataModel);
}
public void UpdateTeacher(TeacherDataModel teacherDataModel)
{
_logger.LogInformation("Updating teacher: {data}", JsonSerializer.Serialize(teacherDataModel));
ArgumentNullException.ThrowIfNull(teacherDataModel);
teacherDataModel.Validate();
var existingTeacher = _storage.GetElementById(teacherDataModel.Id)
?? throw new ElementNotFoundException(teacherDataModel.Id);
_storage.UpdElement(teacherDataModel);
}
public void DeleteTeacher(string id)
{
_logger.LogInformation("Deleting teacher with ID: {id}", id);
ValidateId(id, "Teacher ID");
var teacher = _storage.GetElementById(id)
?? throw new ElementNotFoundException(id);
_storage.DelElement(teacher);
}
public List<TeacherDataModel> GetAllTeachers()
{
_logger.LogInformation("Getting all teachers");
return _storage.GetList() ?? throw new NullListException();
}
public TeacherDataModel? GetTeacherById(string teacherId)
{
_logger.LogInformation("Getting teacher by ID: {teacherId}", teacherId);
ValidateId(teacherId, "Teacher ID");
return _storage.GetElementById(teacherId);
}
public TeacherDataModel? GetTeacherByUserId(string userId)
{
_logger.LogInformation("Getting teacher by user ID: {userId}", userId);
ValidateId(userId, "User ID");
return _storage.GetElementByUserId(userId);
}
public List<TeacherDataModel> GetTeachersByPosition(TeacherPositionType position)
{
_logger.LogInformation("Getting teachers by position: {position}", position);
if (position == TeacherPositionType.None)
throw new ValidationException("Position must be specified");
return _storage.GetListByPosition(position) ?? throw new NullListException();
}
public List<TeacherDataModel> GetTeachersByPositions(IEnumerable<TeacherPositionType> positions)
{
_logger.LogInformation("Getting teachers by multiple positions");
ArgumentNullException.ThrowIfNull(positions);
var result = new List<TeacherDataModel>();
foreach (var position in positions)
{
if (position != TeacherPositionType.None)
{
var teachers = _storage.GetListByPosition(position);
if (teachers != null)
result.AddRange(teachers);
}
}
return result;
}
public List<TeacherDataModel> GetTeachersHiredAfterDate(DateTime date)
{
_logger.LogInformation("Getting teachers hired after: {date}", date.ToShortDateString());
return _storage.GetListByHireDateRange(date.AddDays(1), DateTime.MaxValue) ?? throw new NullListException();
}
public List<TeacherDataModel> GetTeachersHiredBeforeDate(DateTime date)
{
_logger.LogInformation("Getting teachers hired before: {date}", date.ToShortDateString());
return _storage.GetListByHireDateRange(DateTime.MinValue, date.AddDays(-1)) ?? throw new NullListException();
}
public List<TeacherDataModel> GetTeachersHiredBetweenDates(DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Getting teachers hired between {startDate} and {endDate}",
startDate.ToShortDateString(), endDate.ToShortDateString());
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
return _storage.GetListByHireDateRange(startDate, endDate) ?? throw new NullListException();
}
public List<TeacherDataModel> GetTeachersByPositionAndHireDate(TeacherPositionType position, DateTime startDate, DateTime endDate)
{
_logger.LogInformation("Getting teachers by position {position} hired between {startDate} and {endDate}",
position, startDate.ToShortDateString(), endDate.ToShortDateString());
if (position == TeacherPositionType.None)
throw new ValidationException("Position must be specified");
if (startDate > endDate)
throw new IncorrectDatesException(startDate, endDate);
var teachers = _storage.GetListByPosition(position) ?? throw new NullListException();
return teachers.Where(t => t.DateHiring >= startDate && t.DateHiring <= endDate).ToList();
}
public int GetTeacherCount()
{
_logger.LogInformation("Getting total teacher count");
return _storage.GetList()?.Count ?? 0;
}
public int GetTeacherCountByPosition(TeacherPositionType position)
{
_logger.LogInformation("Getting teacher count by position: {position}", position);
if (position == TeacherPositionType.None)
throw new ValidationException("Position must be specified");
return _storage.GetListByPosition(position)?.Count ?? 0;
}
public Dictionary<TeacherPositionType, int> GetTeacherPositionDistribution()
{
_logger.LogInformation("Getting teacher position distribution");
var teachers = _storage.GetList() ?? throw new NullListException();
return teachers
.GroupBy(t => t.Position)
.ToDictionary(g => g.Key, g => g.Count());
}
private void ValidateId(string id, string paramName)
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(paramName);
if (!Guid.TryParse(id, out _))
throw new ValidationException($"{paramName} must be in valid GUID format");
}
}

View File

@@ -10,10 +10,10 @@ using System.Data;
namespace UniversityAllExpelled_BusinessLogic.Implementations;
internal class UserBusinessLogicContract(IUserStorageContract userStorageContract, ILogger logger) : IUserBusinessLogicContract
internal class UserBusinessLogicContract(IUserStorageContract userStorageContract, ILogger<UserBusinessLogicContract> logger) : IUserBusinessLogicContract
{
private readonly IUserStorageContract _userStorageContract = userStorageContract;
private readonly ILogger _logger = logger;
private readonly ILogger<UserBusinessLogicContract> _logger;
public List<UserDataModel> GetAllUsers()
{

View File

@@ -6,4 +6,15 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UniversityAllExpelled_Models\UniversityAllExpelled_Models.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="UniversityAllExpelled_WebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,16 @@
using Microsoft.EntityFrameworkCore;
using System.Threading;
using System.Threading.Tasks;
using UniversityAllExpelled_DataBase.Models;
namespace UniversityAllExpelled_DataBase
{
public interface IUniversityDbContext
{
DbSet<User> Users { get; }
DbSet<Student> Students { get; }
DbSet<Teacher> Teachers { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
}

View File

@@ -14,9 +14,9 @@ namespace UniversityAllExpelled_DataBase.Implementations;
internal class EducationLessonsStorageContract : IEducationLessonsStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public EducationLessonsStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public EducationLessonsStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;

View File

@@ -141,4 +141,19 @@ internal class EducationStorageContract : IEducationStorageContract
_dbContext.Educations.Remove(educationEntity);
_dbContext.SaveChanges();
}
public List<EducationDataModel> GetAllEducationByLessons()
{
var educationLessons = _dbContext.EducationLessons
.AsNoTracking()
.Include(el => el.Education)
.ToList();
var result = educationLessons
.Where(el => el.Education != null)
.Select(el => _mapper.Map<EducationDataModel>(el.Education))
.ToList();
return result;
}
}

View File

@@ -9,9 +9,9 @@ namespace UniversityAllExpelled_DataBase.Implementations
internal class LessonStorageContract : ILessonStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public LessonStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public LessonStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));

View File

@@ -9,9 +9,9 @@ namespace UniversityAllExpelled_DataBase.Implementations
internal class PaymentStorageContract : IPaymentStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public PaymentStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public PaymentStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));

View File

@@ -12,9 +12,9 @@ namespace UniversityAllExpelled_DataBase.Implementations;
internal class SalaryStorageContract : ISalaryStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public SalaryStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public SalaryStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;

View File

@@ -10,9 +10,9 @@ namespace UniversityAllExpelled_DataBase.Implementations
internal class StudentStorageContract : IStudentStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public StudentStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public StudentStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));

View File

@@ -10,9 +10,9 @@ namespace UniversityAllExpelled_DataBase.Implementations;
internal class TeacherStorageContract : ITeacherStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public TeacherStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public TeacherStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
@@ -93,7 +93,7 @@ internal class TeacherStorageContract : ITeacherStorageContract
var teacherEntity = _dbContext.Teachers
.AsNoTracking()
.FirstOrDefault(t => t.Userid == userId);
.FirstOrDefault(t => t.UserId == userId);
return teacherEntity != null ? _mapper.Map<TeacherDataModel>(teacherEntity) : null;
}

View File

@@ -10,10 +10,10 @@ namespace UniversityAllExpelled_DataBase.Implementations;
internal class UserStorageContract : IUserStorageContract
{
private readonly UniversityAllExpelledDbContext _dbContext;
private readonly Mapper _mapper;
private readonly IMapper _mapper;
public UserStorageContract(UniversityAllExpelledDbContext dbContext, Mapper mapper)
public UserStorageContract(UniversityAllExpelledDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;

View File

@@ -0,0 +1,413 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using UniversityAllExpelled_DataBase;
#nullable disable
namespace UniversityAllExpelled_DataBase.Migrations
{
[DbContext(typeof(UniversityAllExpelledDbContext))]
[Migration("20250519195820_FirstMigration")]
partial class FirstMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Education", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<float>("Amount")
.HasColumnType("real");
b.Property<DateTime>("EndDate")
.HasColumnType("date");
b.Property<DateTime>("StartDate")
.HasColumnType("date");
b.Property<string>("TeacherId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("TeacherId", "Active")
.HasFilter("\"Active\" = TRUE");
b.ToTable("Educations");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.EducationLessons", b =>
{
b.Property<string>("EducationId")
.HasColumnType("text");
b.Property<string>("LessonsId")
.HasColumnType("text");
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("LessonId")
.HasColumnType("text");
b.HasKey("EducationId", "LessonsId");
b.HasIndex("LessonId");
b.ToTable("EducationLessons");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Lesson", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("EndDate")
.HasColumnType("timestamp");
b.Property<bool>("IsActive")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<double>("Price")
.HasColumnType("numeric(18,2)");
b.Property<string>("SalaryId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("StartDate")
.HasColumnType("timestamp");
b.Property<string>("StudentId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SalaryId")
.IsUnique();
b.HasIndex("StudentId", "StartDate", "EndDate");
b.ToTable("Lessons");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Payment", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<double>("Arrears")
.HasColumnType("numeric(18,2)");
b.Property<DateTime>("DateOfpayment")
.HasColumnType("date");
b.Property<double>("PaidAmount")
.HasColumnType("numeric(18,2)");
b.Property<bool>("PaidOf")
.HasColumnType("boolean");
b.Property<string>("StudentId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("StudentsId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("StudentId");
b.HasIndex("StudentsId", "PaidOf")
.HasFilter("\"PaidOf\" = FALSE");
b.ToTable("Payments");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Salary", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<double>("Count")
.HasColumnType("numeric(18,2)");
b.Property<DateTime>("Date")
.HasColumnType("date");
b.Property<string>("TeacherId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Salaries");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<int>("Course")
.HasColumnType("integer");
b.Property<int>("Faculty")
.HasColumnType("integer");
b.Property<int>("Groop")
.HasColumnType("integer");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId1")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserId1");
b.ToTable("Students");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("DateHiring")
.HasColumnType("date");
b.Property<int>("Position")
.HasColumnType("integer");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId1")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserId1");
b.ToTable("Teachers");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.User", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("BirthDate")
.HasColumnType("date");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("FIO")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("character varying(150)");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<string>("Login")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("PhoneNomber")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<int>("Role")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("Email")
.IsUnique();
b.HasIndex("Login")
.IsUnique();
b.HasIndex("PhoneNomber")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Education", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Teacher", "Teacher")
.WithMany("Educations")
.HasForeignKey("TeacherId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Teacher");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.EducationLessons", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Education", "Education")
.WithMany()
.HasForeignKey("EducationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Lesson", "Lesson")
.WithMany()
.HasForeignKey("LessonId");
b.Navigation("Education");
b.Navigation("Lesson");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Lesson", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Salary", "Salary")
.WithOne("Lesson")
.HasForeignKey("UniversityAllExpelled_DataBase.Models.Lesson", "SalaryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", "Student")
.WithMany()
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Salary");
b.Navigation("Student");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Payment", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", null)
.WithMany("Payments")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", "Student")
.WithMany()
.HasForeignKey("StudentsId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Student");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.User", null)
.WithMany("Students")
.HasForeignKey("UserId1");
b.Navigation("User");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.User", null)
.WithMany("Teachers")
.HasForeignKey("UserId1");
b.Navigation("User");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Salary", b =>
{
b.Navigation("Lesson");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.Navigation("Payments");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.Navigation("Educations");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.User", b =>
{
b.Navigation("Students");
b.Navigation("Teachers");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,310 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace UniversityAllExpelled_DataBase.Migrations
{
/// <inheritdoc />
public partial class FirstMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Salaries",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
TeacherId = table.Column<string>(type: "text", nullable: false),
Count = table.Column<double>(type: "numeric(18,2)", nullable: false),
Date = table.Column<DateTime>(type: "date", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Salaries", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Login = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
Password = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Role = table.Column<int>(type: "integer", nullable: false),
FIO = table.Column<string>(type: "character varying(150)", maxLength: 150, nullable: false),
BirthDate = table.Column<DateTime>(type: "date", nullable: false),
PhoneNomber = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Email = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Students",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<string>(type: "text", nullable: false),
Faculty = table.Column<int>(type: "integer", nullable: false),
Groop = table.Column<int>(type: "integer", nullable: false),
Course = table.Column<int>(type: "integer", nullable: false),
UserId1 = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Students", x => x.Id);
table.ForeignKey(
name: "FK_Students_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Students_Users_UserId1",
column: x => x.UserId1,
principalTable: "Users",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Teachers",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<string>(type: "text", nullable: false),
DateHiring = table.Column<DateTime>(type: "date", nullable: false),
UserId1 = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Teachers", x => x.Id);
table.ForeignKey(
name: "FK_Teachers_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_Teachers_Users_UserId1",
column: x => x.UserId1,
principalTable: "Users",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Lessons",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Price = table.Column<double>(type: "numeric(18,2)", nullable: false),
StartDate = table.Column<DateTime>(type: "timestamp", nullable: false),
EndDate = table.Column<DateTime>(type: "timestamp", nullable: false),
StudentId = table.Column<string>(type: "text", nullable: false),
SalaryId = table.Column<string>(type: "text", nullable: false),
IsActive = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Lessons", x => x.Id);
table.ForeignKey(
name: "FK_Lessons_Salaries_SalaryId",
column: x => x.SalaryId,
principalTable: "Salaries",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Lessons_Students_StudentId",
column: x => x.StudentId,
principalTable: "Students",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Payments",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
StudentId = table.Column<string>(type: "text", nullable: false),
PaidAmount = table.Column<double>(type: "numeric(18,2)", nullable: false),
Arrears = table.Column<double>(type: "numeric(18,2)", nullable: false),
DateOfpayment = table.Column<DateTime>(type: "date", nullable: false),
PaidOf = table.Column<bool>(type: "boolean", nullable: false),
StudentsId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Payments", x => x.Id);
table.ForeignKey(
name: "FK_Payments_Students_StudentId",
column: x => x.StudentId,
principalTable: "Students",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Payments_Students_StudentsId",
column: x => x.StudentsId,
principalTable: "Students",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Educations",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
TeacherId = table.Column<string>(type: "text", nullable: false),
Amount = table.Column<float>(type: "real", nullable: false),
StartDate = table.Column<DateTime>(type: "date", nullable: false),
EndDate = table.Column<DateTime>(type: "date", nullable: false),
Active = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Educations", x => x.Id);
table.ForeignKey(
name: "FK_Educations_Teachers_TeacherId",
column: x => x.TeacherId,
principalTable: "Teachers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EducationLessons",
columns: table => new
{
EducationId = table.Column<string>(type: "text", nullable: false),
LessonsId = table.Column<string>(type: "text", nullable: false),
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
LessonId = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationLessons", x => new { x.EducationId, x.LessonsId });
table.ForeignKey(
name: "FK_EducationLessons_Educations_EducationId",
column: x => x.EducationId,
principalTable: "Educations",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_EducationLessons_Lessons_LessonId",
column: x => x.LessonId,
principalTable: "Lessons",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_EducationLessons_LessonId",
table: "EducationLessons",
column: "LessonId");
migrationBuilder.CreateIndex(
name: "IX_Educations_TeacherId_Active",
table: "Educations",
columns: new[] { "TeacherId", "Active" },
filter: "\"Active\" = TRUE");
migrationBuilder.CreateIndex(
name: "IX_Lessons_SalaryId",
table: "Lessons",
column: "SalaryId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Lessons_StudentId_StartDate_EndDate",
table: "Lessons",
columns: new[] { "StudentId", "StartDate", "EndDate" });
migrationBuilder.CreateIndex(
name: "IX_Payments_StudentId",
table: "Payments",
column: "StudentId");
migrationBuilder.CreateIndex(
name: "IX_Payments_StudentsId_PaidOf",
table: "Payments",
columns: new[] { "StudentsId", "PaidOf" },
filter: "\"PaidOf\" = FALSE");
migrationBuilder.CreateIndex(
name: "IX_Students_UserId",
table: "Students",
column: "UserId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Students_UserId1",
table: "Students",
column: "UserId1");
migrationBuilder.CreateIndex(
name: "IX_Teachers_UserId",
table: "Teachers",
column: "UserId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Teachers_UserId1",
table: "Teachers",
column: "UserId1");
migrationBuilder.CreateIndex(
name: "IX_Users_Email",
table: "Users",
column: "Email",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_Login",
table: "Users",
column: "Login",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_PhoneNomber",
table: "Users",
column: "PhoneNomber",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "EducationLessons");
migrationBuilder.DropTable(
name: "Payments");
migrationBuilder.DropTable(
name: "Educations");
migrationBuilder.DropTable(
name: "Lessons");
migrationBuilder.DropTable(
name: "Teachers");
migrationBuilder.DropTable(
name: "Salaries");
migrationBuilder.DropTable(
name: "Students");
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@@ -0,0 +1,410 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using UniversityAllExpelled_DataBase;
#nullable disable
namespace UniversityAllExpelled_DataBase.Migrations
{
[DbContext(typeof(UniversityAllExpelledDbContext))]
partial class UniversityAllExpelledDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Education", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<float>("Amount")
.HasColumnType("real");
b.Property<DateTime>("EndDate")
.HasColumnType("date");
b.Property<DateTime>("StartDate")
.HasColumnType("date");
b.Property<string>("TeacherId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("TeacherId", "Active")
.HasFilter("\"Active\" = TRUE");
b.ToTable("Educations");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.EducationLessons", b =>
{
b.Property<string>("EducationId")
.HasColumnType("text");
b.Property<string>("LessonsId")
.HasColumnType("text");
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("LessonId")
.HasColumnType("text");
b.HasKey("EducationId", "LessonsId");
b.HasIndex("LessonId");
b.ToTable("EducationLessons");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Lesson", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("EndDate")
.HasColumnType("timestamp");
b.Property<bool>("IsActive")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<double>("Price")
.HasColumnType("numeric(18,2)");
b.Property<string>("SalaryId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("StartDate")
.HasColumnType("timestamp");
b.Property<string>("StudentId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SalaryId")
.IsUnique();
b.HasIndex("StudentId", "StartDate", "EndDate");
b.ToTable("Lessons");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Payment", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<double>("Arrears")
.HasColumnType("numeric(18,2)");
b.Property<DateTime>("DateOfpayment")
.HasColumnType("date");
b.Property<double>("PaidAmount")
.HasColumnType("numeric(18,2)");
b.Property<bool>("PaidOf")
.HasColumnType("boolean");
b.Property<string>("StudentId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("StudentsId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("StudentId");
b.HasIndex("StudentsId", "PaidOf")
.HasFilter("\"PaidOf\" = FALSE");
b.ToTable("Payments");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Salary", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<double>("Count")
.HasColumnType("numeric(18,2)");
b.Property<DateTime>("Date")
.HasColumnType("date");
b.Property<string>("TeacherId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Salaries");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<int>("Course")
.HasColumnType("integer");
b.Property<int>("Faculty")
.HasColumnType("integer");
b.Property<int>("Groop")
.HasColumnType("integer");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId1")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserId1");
b.ToTable("Students");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("DateHiring")
.HasColumnType("date");
b.Property<int>("Position")
.HasColumnType("integer");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId1")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.HasIndex("UserId1");
b.ToTable("Teachers");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.User", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTime>("BirthDate")
.HasColumnType("date");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("FIO")
.IsRequired()
.HasMaxLength(150)
.HasColumnType("character varying(150)");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<string>("Login")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("PhoneNomber")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<int>("Role")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("Email")
.IsUnique();
b.HasIndex("Login")
.IsUnique();
b.HasIndex("PhoneNomber")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Education", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Teacher", "Teacher")
.WithMany("Educations")
.HasForeignKey("TeacherId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Teacher");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.EducationLessons", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Education", "Education")
.WithMany()
.HasForeignKey("EducationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Lesson", "Lesson")
.WithMany()
.HasForeignKey("LessonId");
b.Navigation("Education");
b.Navigation("Lesson");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Lesson", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Salary", "Salary")
.WithOne("Lesson")
.HasForeignKey("UniversityAllExpelled_DataBase.Models.Lesson", "SalaryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", "Student")
.WithMany()
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Salary");
b.Navigation("Student");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Payment", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", null)
.WithMany("Payments")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.Student", "Student")
.WithMany()
.HasForeignKey("StudentsId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Student");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.User", null)
.WithMany("Students")
.HasForeignKey("UserId1");
b.Navigation("User");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.HasOne("UniversityAllExpelled_DataBase.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("UniversityAllExpelled_DataBase.Models.User", null)
.WithMany("Teachers")
.HasForeignKey("UserId1");
b.Navigation("User");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Salary", b =>
{
b.Navigation("Lesson");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Student", b =>
{
b.Navigation("Payments");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.Teacher", b =>
{
b.Navigation("Educations");
});
modelBuilder.Entity("UniversityAllExpelled_DataBase.Models.User", b =>
{
b.Navigation("Students");
b.Navigation("Teachers");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,43 +1,41 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Education : EducationDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Education(string id, string teacherId, float amount, DateTime startDate, DateTime endDate, bool active)
: base(id, teacherId, amount, startDate, endDate, active) { }
public class Education : EducationDataModel
{
public Education(string id, string teacherId, float amount, DateTime startDate, DateTime endDate, bool active)
: base(id, teacherId, amount, startDate, endDate, active) { }
protected Education()
: base(string.Empty, string.Empty, 0f, DateTime.MinValue, DateTime.MinValue, false) { }
protected Education()
: base(string.Empty, string.Empty, 0f, DateTime.MinValue, DateTime.MinValue, false) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
[Range(0.01, float.MaxValue)]
public new float Amount { get; set; }
[Required]
[Range(0.01, float.MaxValue)]
[Column(TypeName = "real")]
public new float Amount { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime EndDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime EndDate { get; set; }
[Required]
public new bool Active { get; set; }
[Required]
public new bool Active { get; set; }
public Teacher? Teacher { get; set; }
}
public Teacher? Teacher { get; set; }
}
}

View File

@@ -1,32 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class EducationLessons : EducationLessonsDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public EducationLessons(string educationId, string lessonsId)
: base(educationId, lessonsId) { }
public class EducationLessons : EducationLessonsDataModel
{
public EducationLessons(string educationId, string lessonsId)
: base(educationId, lessonsId) { }
protected EducationLessons()
: base(string.Empty, string.Empty) { }
protected EducationLessons()
: base(string.Empty, string.Empty) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public new string EducationId { get; set; }
[Required]
public new string EducationId { get; set; }
[Required]
public new string LessonsId { get; set; }
[Required]
public new string LessonsId { get; set; }
public Education? Education { get; set; }
public Lesson? Lesson { get; set; }
public Education? Education { get; set; }
public Lesson? Lesson { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UniversityAllExpelled_DataBase.Models;
public class LoginRequest
{
public string Login { get; set; }
public string Password { get; set; }
}

View File

@@ -0,0 +1,40 @@
using System.ComponentModel.DataAnnotations;
namespace UniversityAllExpelled_Models.DTOs
{
public class RegisterRequest
{
[Required]
public string FIO { get; set; } = "";
[Required]
public string Login { get; set; } = "";
[Required, EmailAddress]
public string Email { get; set; } = "";
[Required, MinLength(10)]
public string PhoneNomber { get; set; } = "";
[Required]
public DateTime BirthDate { get; set; }
[Required, MinLength(8)]
public string Password { get; set; } = "";
[Required]
public string ConfirmPassword { get; set; } = "";
[Required]
public string Role { get; set; } = "";
// Только для студента
public string? Faculty { get; set; }
public string? Groop { get; set; }
public int? Course { get; set; }
// Только для преподавателя
public string? Position { get; set; }
public DateTime? DateHiring { get; set; }
}
}

View File

@@ -1,37 +1,35 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Salary : SalaryDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Salary(string id, string teacherId, double count, DateTime date)
: base(id, teacherId, count, date) { }
public class Salary : SalaryDataModel
{
public Salary(string id, string teacherId, double count, DateTime date)
: base(id, teacherId, count, date) { }
protected Salary()
: base(string.Empty, string.Empty, 0, DateTime.MinValue) { }
protected Salary()
: base(string.Empty, string.Empty, 0, DateTime.MinValue) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
public new double Count { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
[Column(TypeName = "numeric(18,2)")] // для правильного хранения decimal в PostgreSQL
public new double Count { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime Date { get; set; }
[ForeignKey("SalaryId")]
public Lesson? Lesson { get; set; }
}
[Required]
[Column(TypeName = "date")]
public new DateTime Date { get; set; }
[InverseProperty(nameof(Lesson.Salary))]
public virtual Lesson? Lesson { get; set; }
}
}

View File

@@ -1,33 +1,38 @@
using System.ComponentModel.DataAnnotations.Schema;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.Enums;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Teacher : TeacherDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Teacher(string id, TeacherPositionType position, string userid, DateTime dateHiring)
: base(id, position, userid, dateHiring) { }
public class Teacher : TeacherDataModel
{
public Teacher(string id, TeacherPositionType position, string userId, DateTime dateHiring)
: base(id, position, userId, dateHiring) { }
protected Teacher()
: base(string.Empty, TeacherPositionType.None, string.Empty, DateTime.MinValue) { }
protected Teacher()
: base(string.Empty, TeacherPositionType.None, string.Empty, DateTime.MinValue) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new TeacherPositionType Position { get; set; }
[Required]
public new TeacherPositionType Position { get; set; }
[Required]
public new string Userid { get; set; }
[Required]
public new string UserId { get; set; } // исправил с UserId на UserId для единообразия
[Required]
[Column(TypeName = "date")]
public new DateTime DateHiring { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime DateHiring { get; set; }
[ForeignKey("TeacherId")]
public List<Education> Educations { get; set; }
public User? User { get; set; }
}
// Навигационные свойства
[InverseProperty(nameof(Education.Teacher))]
public virtual List<Education> Educations { get; set; } = new List<Education>();
public virtual User? User { get; set; }
}
}

View File

@@ -1,24 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels;
using UniversityAllExpelled_Models.Enums;
namespace UniversityAllExpelled_DataBase.Models;
internal class User : UserDataModel
public class User : UserDataModel
{
public User(string id, string login, string password, SystemRoleType role, string fio, DateTime birthdate,
string phoneNomber, string email, bool isDeleted) : base(id, login, password, role, fio, birthdate,
phoneNomber, email, isDeleted) {}
protected User()
: base(string.Empty, string.Empty, string.Empty, SystemRoleType.None,
string.Empty, DateTime.MinValue, string.Empty, string.Empty, false){}
public User(string id, string login, string password, SystemRoleType role, string fio, DateTime birthDate,
string phoneNomber, string email, bool isDeleted)
: base(id, login, password, role, fio, birthDate, phoneNomber, email, isDeleted)
{ }
public User() : base(string.Empty, string.Empty, string.Empty, SystemRoleType.None,
string.Empty, DateTime.MinValue, string.Empty, string.Empty, false)
{ }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
@@ -44,7 +44,7 @@ internal class User : UserDataModel
[Required]
[StringLength(20)]
public new string PhoneNomber { get; set; }
public new string PhoneNomber { get; set; }
[Required]
[StringLength(100)]
@@ -52,12 +52,11 @@ internal class User : UserDataModel
[Required]
public new bool IsDeleted { get; set; }
[ForeignKey("UserId")]
public List<Student> Students { get; set; }
[ForeignKey("UserId")]
public List<Teacher> Teachers { get; set; }
[InverseProperty(nameof(Student.User))]
public virtual List<Student> Students { get; set; } = new List<Student>();
[InverseProperty(nameof(Teacher.User))]
public virtual List<Teacher> Teachers { get; set; } = new List<Teacher>();
}

View File

@@ -4,7 +4,7 @@ using UniversityAllExpelled_Models.Infrostructure;
namespace UniversityAllExpelled_DataBase;
internal class UniversityAllExpelledDbContext : DbContext
internal class UniversityAllExpelledDbContext : DbContext, IUniversityDbContext
{
private readonly IConfigurationDatabase _configurationDatabase;
@@ -47,7 +47,7 @@ internal class UniversityAllExpelledDbContext : DbContext
// Настройка Teacher
modelBuilder.Entity<Teacher>()
.HasIndex(t => t.Userid)
.HasIndex(t => t.UserId)
.IsUnique();
// Настройка Lesson
@@ -74,7 +74,7 @@ internal class UniversityAllExpelledDbContext : DbContext
modelBuilder.Entity<Teacher>()
.HasOne(t => t.User)
.WithMany()
.HasForeignKey(t => t.Userid)
.HasForeignKey(t => t.UserId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Payment>()

View File

@@ -15,5 +15,8 @@
<ItemGroup>
<ProjectReference Include="..\UniversityAllExpelled_Models\UniversityAllExpelled_Models.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="UniversityAllExpelled_WebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
</Project>

View File

@@ -1,43 +1,41 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Education : EducationDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Education(string id, string teacherId, float amount, DateTime startDate, DateTime endDate, bool active)
: base(id, teacherId, amount, startDate, endDate, active) { }
public class Education : EducationDataModel
{
public Education(string id, string teacherId, float amount, DateTime startDate, DateTime endDate, bool active)
: base(id, teacherId, amount, startDate, endDate, active) { }
protected Education()
: base(string.Empty, string.Empty, 0f, DateTime.MinValue, DateTime.MinValue, false) { }
protected Education()
: base(string.Empty, string.Empty, 0f, DateTime.MinValue, DateTime.MinValue, false) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
[Range(0.01, float.MaxValue)]
public new float Amount { get; set; }
[Required]
[Range(0.01, float.MaxValue)]
[Column(TypeName = "real")]
public new float Amount { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime EndDate { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime EndDate { get; set; }
[Required]
public new bool Active { get; set; }
[Required]
public new bool Active { get; set; }
public Teacher? Teacher { get; set; }
}
public Teacher? Teacher { get; set; }
}
}

View File

@@ -1,32 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class EducationLessons : EducationLessonsDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public EducationLessons(string educationId, string lessonsId)
: base(educationId, lessonsId) { }
public class EducationLessons : EducationLessonsDataModel
{
public EducationLessons(string educationId, string lessonsId)
: base(educationId, lessonsId) { }
protected EducationLessons()
: base(string.Empty, string.Empty) { }
protected EducationLessons()
: base(string.Empty, string.Empty) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public new string EducationId { get; set; }
[Required]
public new string EducationId { get; set; }
[Required]
public new string LessonsId { get; set; }
[Required]
public new string LessonsId { get; set; }
public Education? Education { get; set; }
public Lesson? Lesson { get; set; }
public Education? Education { get; set; }
public Lesson? Lesson { get; set; }
}
}

View File

@@ -3,56 +3,57 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
[Table("Lessons")]
internal class Lesson : LessonDataModel
namespace UniversityAllExpelled_DataBase.Models
{
// Конструктор для EF Core
protected Lesson()
: base(string.Empty, string.Empty, 0, DateTime.MinValue, DateTime.MinValue,
string.Empty, string.Empty, false)
[Table("Lessons")]
public class Lesson : LessonDataModel
{
// Конструктор для EF Core
protected Lesson()
: base(string.Empty, string.Empty, 0, DateTime.MinValue, DateTime.MinValue,
string.Empty, string.Empty, false)
{
}
public Lesson(string id, string name, double price, DateTime startDate,
DateTime endDate, string studentId, string salaryId, bool isActive)
: base(id, name, price, startDate, endDate, studentId, salaryId, isActive)
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
[StringLength(100)]
public new string Name { get; set; }
[Required]
[Column(TypeName = "numeric(18,2)")]
[Range(0.01, double.MaxValue)]
public new double Price { get; set; }
[Required]
[Column(TypeName = "timestamp")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "timestamp")]
public new DateTime EndDate { get; set; }
[Required]
[ForeignKey(nameof(Student))]
public new string StudentId { get; set; }
[ForeignKey(nameof(Salary))]
public new string SalaryId { get; set; }
[Required]
public new bool IsActive { get; set; }
// Навигационные свойства
public Student? Student { get; set; }
public Salary? Salary { get; set; }
}
public Lesson(string id, string name, double price, DateTime startDate,
DateTime endDate, string studentId, string salaryId, bool isActive)
: base(id, name, price, startDate, endDate, studentId, salaryId, isActive)
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
[StringLength(100)]
public new string Name { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
[Range(0.01, double.MaxValue)]
public new double Price { get; set; }
[Required]
[Column(TypeName = "datetime2")]
public new DateTime StartDate { get; set; }
[Required]
[Column(TypeName = "datetime2")]
public new DateTime EndDate { get; set; }
[Required]
[ForeignKey(nameof(Student))]
public new string StudentId { get; set; }
[ForeignKey(nameof(Salary))]
public new string SalaryId { get; set; }
[Required]
public new bool IsActive { get; set; }
// Навигационные свойства
public Student? Student { get; set; }
public Salary? Salary { get; set; }
}
}

View File

@@ -1,18 +1,19 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Client;
namespace UniversityAllExpelled_DataBase.Models
{
[Table("Payments")]
internal class Payment : PaymentDataModel
public class Payment : PaymentDataModel
{
protected Payment()
: base(string.Empty, string.Empty, 0, 0, DateTime.Now, false)
{
}
public Payment(string id, string studentId, double paidAmount, double arrears,DateTime dateOfpayment, bool paidOf)
public Payment(string id, string studentId, double paidAmount, double arrears, DateTime dateOfpayment, bool paidOf)
: base(id, studentId, paidAmount, arrears, dateOfpayment, paidOf)
{
}
@@ -23,19 +24,20 @@ namespace UniversityAllExpelled_DataBase.Models
[Required]
[ForeignKey(nameof(Student))]
public new string StudentsId { get; set; }
public new string StudentId { get; set; } // Исправлено с StudentsId на StudentId
[Required]
[Column(TypeName = "decimal(18,2)")]
[Column(TypeName = "numeric(18,2)")] // PostgreSQL использует numeric для decimal
[Range(0, double.MaxValue)]
public new double PaidAmount { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
[Column(TypeName = "numeric(18,2)")]
[Range(0, double.MaxValue)]
public new double Arrears { get; set; }
[Required]
[Column(TypeName = "date")] // Добавлено для явного типа даты
public new DateTime DateOfpayment { get; set; }
[Required]
@@ -43,4 +45,4 @@ namespace UniversityAllExpelled_DataBase.Models
public virtual Student? Student { get; set; }
}
}
}

View File

@@ -1,37 +1,35 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Salary : SalaryDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Salary(string id, string teacherId, double count, DateTime date)
: base(id, teacherId, count, date) { }
public class Salary : SalaryDataModel
{
public Salary(string id, string teacherId, double count, DateTime date)
: base(id, teacherId, count, date) { }
protected Salary()
: base(string.Empty, string.Empty, 0, DateTime.MinValue) { }
protected Salary()
: base(string.Empty, string.Empty, 0, DateTime.MinValue) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
public new string TeacherId { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
public new double Count { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
[Column(TypeName = "numeric(18,2)")] // для правильного хранения decimal в PostgreSQL
public new double Count { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime Date { get; set; }
[ForeignKey("SalaryId")]
public Lesson? Lesson { get; set; }
}
[Required]
[Column(TypeName = "date")]
public new DateTime Date { get; set; }
[InverseProperty(nameof(Lesson.Salary))]
public virtual Lesson? Lesson { get; set; }
}
}

View File

@@ -1,44 +1,39 @@
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels.Client;
using UniversityAllExpelled_Models.Enums;
using System.ComponentModel.DataAnnotations;
namespace UniversityAllExpelled_DataBase.Models;
[Table("Students")]
internal class Student : StudentDataModel
namespace UniversityAllExpelled_DataBase.Models
{
// Конструктор для Entity Framework
protected Student()
: base(string.Empty, string.Empty, FacultyType.None, GroopType.None, 0)
[Table("Students")]
public class Student : StudentDataModel
{
// Конструктор для Entity Framework
protected Student() : base(string.Empty, string.Empty, FacultyType.None, GroopType.None, 0) { }
public Student(string id, string userId, FacultyType faculty, GroopType groop, int course)
: base(id, userId, faculty, groop, course)
{
}
// Переопределяем Id чтобы добавить DatabaseGenerated
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override string Id { get; set; }
[ForeignKey(nameof(User))]
public override string UserId { get; set; }
public override FacultyType Faculty { get; set; }
public override GroopType Groop { get; set; }
public override int Course { get; set; }
// Навигационные свойства
public virtual User? User { get; set; }
[InverseProperty(nameof(Payment.Student))]
public virtual List<Payment> Payments { get; set; } = new List<Payment>();
}
public Student(string id, string userId, FacultyType faculty, GroopType groop, int course)
: base(id, userId, faculty, groop, course)
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
[ForeignKey(nameof(User))]
public new string UserId { get; set; }
[Required]
public new FacultyType Faculty { get; set; }
[Required]
public new GroopType Groop { get; set; }
[Required]
[Range(1, 6)]
public new int Course { get; set; }
[ForeignKey("StudentId")]
public List<Payment> Payment { get; set; }
public User? User { get; set; }
}
}

View File

@@ -1,33 +1,38 @@
using System.ComponentModel.DataAnnotations.Schema;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.Enums;
using UniversityAllExpelled_Models.DataModels.Worker;
namespace UniversityAllExpelled_DataBase.Models;
internal class Teacher : TeacherDataModel
namespace UniversityAllExpelled_DataBase.Models
{
public Teacher(string id, TeacherPositionType position, string userid, DateTime dateHiring)
: base(id, position, userid, dateHiring) { }
public class Teacher : TeacherDataModel
{
public Teacher(string id, TeacherPositionType position, string userId, DateTime dateHiring)
: base(id, position, userId, dateHiring) { }
protected Teacher()
: base(string.Empty, TeacherPositionType.None, string.Empty, DateTime.MinValue) { }
protected Teacher()
: base(string.Empty, TeacherPositionType.None, string.Empty, DateTime.MinValue) { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
[Required]
public new TeacherPositionType Position { get; set; }
[Required]
public new TeacherPositionType Position { get; set; }
[Required]
public new string Userid { get; set; }
[Required]
public new string UserId { get; set; } // исправил с UserId на UserId для единообразия
[Required]
[Column(TypeName = "date")]
public new DateTime DateHiring { get; set; }
[Required]
[Column(TypeName = "date")]
public new DateTime DateHiring { get; set; }
[ForeignKey("TeacherId")]
public List<Education> Educations { get; set; }
public User? User { get; set; }
}
// Навигационные свойства
[InverseProperty(nameof(Education.Teacher))]
public virtual List<Education> Educations { get; set; } = new List<Education>();
public virtual User? User { get; set; }
}
}

View File

@@ -1,24 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using UniversityAllExpelled_Models.DataModels;
using UniversityAllExpelled_Models.Enums;
namespace UniversityAllExpelled_DataBase.Models;
internal class User : UserDataModel
public class User : UserDataModel
{
public User(string id, string login, string password, SystemRoleType role, string fio, DateTime birthdate,
string phoneNomber, string email, bool isDeleted) : base(id, login, password, role, fio, birthdate,
phoneNomber, email, isDeleted) {}
protected User()
: base(string.Empty, string.Empty, string.Empty, SystemRoleType.None,
string.Empty, DateTime.MinValue, string.Empty, string.Empty, false){}
public User(string id, string login, string password, SystemRoleType role, string fio, DateTime birthDate,
string phoneNomber, string email, bool isDeleted)
: base(id, login, password, role, fio, birthDate, phoneNomber, email, isDeleted)
{ }
public User() : base(string.Empty, string.Empty, string.Empty, SystemRoleType.None,
string.Empty, DateTime.MinValue, string.Empty, string.Empty, false)
{ }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new string Id { get; set; }
@@ -44,7 +44,7 @@ internal class User : UserDataModel
[Required]
[StringLength(20)]
public new string PhoneNomber { get; set; }
public new string PhoneNomber { get; set; }
[Required]
[StringLength(100)]
@@ -52,12 +52,11 @@ internal class User : UserDataModel
[Required]
public new bool IsDeleted { get; set; }
[ForeignKey("UserId")]
public List<Student> Students { get; set; }
[ForeignKey("UserId")]
public List<Teacher> Teachers { get; set; }
[InverseProperty(nameof(Student.User))]
public virtual List<Student> Students { get; set; } = new List<Student>();
[InverseProperty(nameof(Teacher.User))]
public virtual List<Teacher> Teachers { get; set; } = new List<Teacher>();
}

View File

@@ -1,5 +1,5 @@
using System.Data;
using UniversityAllExpelled_Models.DataModels;
using UniversityAllExpelled_Models.DataModels.Client;
using UniversityAllExpelled_Models.Enums;

View File

@@ -2,19 +2,18 @@
using UniversityAllExpelled_Models.DataModels;
namespace UniversityAllExpelled_Models.BusinessLogicContracts
{
interface IUserBusinessLogicContract
{
List<UserDataModel> GetAllUsers();
List<UserDataModel> GetAllActiveUsers(bool IsDeleted = false);
List<UserDataModel> GetAllUserByBirthDate(DateTime fromDate, DateTime toDate, bool IsDeleted = false);
UserDataModel GetUserByData(string data);
void InsertUser(UserDataModel userDataModel);
void UpdateUser(UserDataModel userDataModel);
void RestoreUser(string Id);
void DeleteUser(string id);
namespace UniversityAllExpelled_Models.BusinessLogicContracts;
interface IUserBusinessLogicContract
{
List<UserDataModel> GetAllUsers();
List<UserDataModel> GetAllActiveUsers(bool IsDeleted = false);
List<UserDataModel> GetAllUserByBirthDate(DateTime fromDate, DateTime toDate, bool IsDeleted = false);
UserDataModel GetUserByData(string data);
void InsertUser(UserDataModel userDataModel);
void UpdateUser(UserDataModel userDataModel);
void RestoreUser(string Id);
void DeleteUser(string id);
}
}

View File

@@ -1,319 +1,30 @@
using Microsoft.Extensions.Logging;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels.Client;
using UniversityAllExpelled_Models.Enums;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.Extensions;
using UniversityAllExpelled_Models.StorageContracts;
using System.Text.Json;
using System.Data;
using UniversityAllExpelled_Models.Infrostructure;
namespace UniversityAllExpelled_BusinessLogic.Implementations
namespace UniversityAllExpelled_Models.DataModels.Client;
public class PaymentLessonDataModel(string paymentId, string lessonId) : IValidation
{
internal class StudentBusinessLogicContract : IStudentBusinessLogicContract
public string PaymentId { get; private set; }
public string LessonId { get; private set; }
public void Validate()
{
private readonly IStudentStorageContract _studentStorage;
private readonly IUserStorageContract _userStorage;
private readonly ILogger<StudentBusinessLogicContract> _logger;
public StudentBusinessLogicContract(
IStudentStorageContract studentStorage,
IUserStorageContract userStorage,
ILogger<StudentBusinessLogicContract> logger)
if (PaymentId.IsEmpty())
{
_studentStorage = studentStorage ?? throw new ArgumentNullException(nameof(studentStorage));
_userStorage = userStorage ?? throw new ArgumentNullException(nameof(userStorage));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
throw new ValidationException("Field PaymentId is empty.");
}
public List<StudentDataModel> GetAllStudents(SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
if (!PaymentId.IsGuid())
{
_logger.LogInformation("Getting all students with role: {Role}, IsDeleted: {IsDeleted}", role, IsDeleted);
try
{
var students = _studentStorage.GetList() ?? throw new DataException("Failed to retrieve students list");
var result = new List<StudentDataModel>();
foreach (var student in students)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted)
{
result.Add(student);
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting all students");
throw;
}
throw new ValidationException("The value in the field PaymentId is not a valid GUID.");
}
public List<StudentDataModel> GetAllStudentsByBirthDate(DateTime startDate, DateTime endDate,
SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
if (LessonId.IsEmpty())
{
_logger.LogInformation(
"Getting students by birth date from {StartDate} to {EndDate}, role: {Role}, IsDeleted: {IsDeleted}",
startDate, endDate, role, IsDeleted);
if (startDate > endDate)
throw new ValidationException("Start date cannot be greater than end date");
try
{
var students = _studentStorage.GetList() ?? throw new DataException("Failed to retrieve students list");
var result = new List<StudentDataModel>();
foreach (var student in students)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted
&& user.BirthDate >= startDate && user.BirthDate <= endDate)
{
result.Add(student);
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting students by birth date");
throw;
}
throw new ValidationException("Field LessonId is empty.");
}
public List<StudentDataModel> GetAllStudentsByFaculty(FacultyType faculty,
SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
if (!LessonId.IsGuid())
{
_logger.LogInformation("Getting students by faculty: {Faculty}, role: {Role}, IsDeleted: {IsDeleted}",
faculty, role, IsDeleted);
try
{
var students = _studentStorage.GetListByFaculty(faculty.ToString())
?? throw new DataException($"Failed to retrieve students for faculty {faculty}");
var result = new List<StudentDataModel>();
foreach (var student in students)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted)
{
result.Add(student);
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting students by faculty");
throw;
}
}
public List<StudentDataModel> GetAllStudentsByGroopType(GroopType groop,
SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
{
_logger.LogInformation("Getting students by group: {Groop}, role: {Role}, IsDeleted: {IsDeleted}",
groop, role, IsDeleted);
try
{
var students = _studentStorage.GetListByGroop(groop.ToString())
?? throw new DataException($"Failed to retrieve students for group {groop}");
var result = new List<StudentDataModel>();
foreach (var student in students)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted)
{
result.Add(student);
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting students by group");
throw;
}
}
public List<StudentDataModel> GetAllStudentsByCource(int course,
SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
{
_logger.LogInformation("Getting students by course: {Course}, role: {Role}, IsDeleted: {IsDeleted}",
course, role, IsDeleted);
if (course < 1 || course > 6)
throw new ValidationException("Course must be between 1 and 6");
try
{
var students = _studentStorage.GetListByCource(course)
?? throw new DataException($"Failed to retrieve students for course {course}");
var result = new List<StudentDataModel>();
foreach (var student in students)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted)
{
result.Add(student);
}
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting students by course");
throw;
}
}
public StudentDataModel? GetStudentByData(string data,
SystemRoleType role = SystemRoleType.student, bool IsDeleted = false)
{
_logger.LogInformation("Getting student by data: {Data}, role: {Role}, IsDeleted: {IsDeleted}",
data, role, IsDeleted);
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentNullException(nameof(data));
try
{
StudentDataModel? student = null;
// Try by student ID
if (data.IsGuid())
student = _studentStorage.GetElementById(data);
// Try by user ID
if (student == null && data.IsGuid())
student = _studentStorage.GetElementByUserId(data);
if (student == null)
{
var user = _userStorage.GetElementById(data)
?? _userStorage.GetElementByPhoneNomber(data)
?? _userStorage.GetListByLogin(data);
if (user != null)
{
student = _studentStorage.GetElementByUserId(user.Id);
}
}
if (student != null)
{
var user = _userStorage.GetElementById(student.UserId);
if (user != null && user.Role == role && user.IsDeleted == IsDeleted)
return student;
}
return null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting student by data");
throw;
}
}
public void InsertStudent(StudentDataModel studentDataModel)
{
_logger.LogInformation("Inserting new student: {StudentData}",
JsonSerializer.Serialize(studentDataModel));
try
{
ArgumentNullException.ThrowIfNull(studentDataModel);
studentDataModel.Validate();
var user = _userStorage.GetElementById(studentDataModel.UserId)
?? throw new ElementNotFoundException($"User with ID {studentDataModel.UserId} not found");
if (user.Role != SystemRoleType.student)
throw new ValidationException("User must have student role");
if (_studentStorage.GetElementByUserId(studentDataModel.UserId) != null)
throw new DuplicateException($"Student for user {studentDataModel.UserId} already exists");
_studentStorage.AddElement(studentDataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while inserting student");
throw;
}
}
public void UpdateStudent(StudentDataModel studentDataModel)
{
_logger.LogInformation("Updating student: {StudentData}",
JsonSerializer.Serialize(studentDataModel));
try
{
ArgumentNullException.ThrowIfNull(studentDataModel);
studentDataModel.Validate();
var existingStudent = _studentStorage.GetElementById(studentDataModel.Id)
?? throw new ElementNotFoundException($"Student with ID {studentDataModel.Id} not found");
if (existingStudent.UserId != studentDataModel.UserId)
throw new ValidationException("Cannot change UserId for existing student");
_studentStorage.UpdElement(studentDataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while updating student");
throw;
}
}
public void RestoreStudent(string id)
{
_logger.LogInformation("Restoring student with ID: {Id}", id);
try
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(nameof(id));
if (!id.IsGuid())
throw new ValidationException("Id must be a valid GUID");
var student = _studentStorage.GetElementById(id)
?? throw new ElementNotFoundException($"Student with ID {id} not found");
var user = _userStorage.GetElementById(student.UserId)
?? throw new DataException($"User data not found for student {id}");
user.IsDeleted = false;
_userStorage.UpdElement(user);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while restoring student");
throw;
}
throw new ValidationException("The value in the field LessonId is not a valid GUID.");
}
}
}

View File

@@ -2,55 +2,54 @@
using UniversityAllExpelled_Models.Exceptions;
using UniversityAllExpelled_Models.Extensions;
using UniversityAllExpelled_Models.Infrostructure;
using System.ComponentModel.DataAnnotations;
using ValidationException = UniversityAllExpelled_Models.Exceptions.ValidationException;
namespace UniversityAllExpelled_Models.DataModels.Client;
public class StudentDataModel(string id, string userId, FacultyType faculty, GroopType groop, int course) : IValidation
namespace UniversityAllExpelled_Models.DataModels.Client
{
public string Id { get; set; } = id;
public string UserId { get; set; } = userId;
public FacultyType Faculty { get; set; } = faculty;
public GroopType Groop { get; set; } = groop;
public int Course { get; set; } = course;
public void Validate()
public class StudentDataModel : IValidation
{
if (Id.IsEmpty())
public StudentDataModel(string id, string userId, FacultyType faculty, GroopType groop, int course)
{
throw new ValidationException("Field Id is empty.");
}
if (!Id.IsGuid())
{
throw new ValidationException("The value in field Id is not a valid GUID.");
Id = id;
UserId = userId;
Faculty = faculty;
Groop = groop;
Course = course;
}
[Key]
public virtual string Id { get; set; }
[Required]
public virtual string UserId { get; set; }
[Required]
public virtual FacultyType Faculty { get; set; }
[Required]
public virtual GroopType Groop { get; set; }
[Required]
[Range(1, 6)]
public virtual int Course { get; set; }
if (UserId.IsEmpty())
public void Validate()
{
throw new ValidationException("Field UserId is empty.");
}
if (!UserId.IsGuid())
{
throw new ValidationException("The value in field UserId is not a valid GUID.");
}
if (string.IsNullOrWhiteSpace(Id))
throw new ValidationException("Field Id is empty.");
if (!Id.IsGuid())
throw new ValidationException("The value in field Id is not a valid GUID.");
if (string.IsNullOrWhiteSpace(UserId))
throw new ValidationException("Field UserId is empty.");
if (!UserId.IsGuid())
throw new ValidationException("The value in field UserId is not a valid GUID.");
if (Faculty == FacultyType.None)
{
throw new ValidationException("Faculty must be specified (cannot be None).");
}
if (Faculty == FacultyType.None)
throw new ValidationException("Faculty must be specified (cannot be None).");
if (Groop == GroopType.None)
throw new ValidationException("Group must be specified (cannot be None).");
if (Groop == GroopType.None)
{
throw new ValidationException("Group must be specified (cannot be None).");
}
// Проверка Course (должен быть от 1 до 6)
if (Course < 1 || Course > 6)
{
throw new ValidationException("Course must be between 1 and 6.");
if (Course < 1 || Course > 6)
throw new ValidationException("Course must be between 1 and 6.");
}
}
}

View File

@@ -14,7 +14,7 @@ namespace UniversityAllExpelled_Models.DataModels.Worker;
public class TeacherDataModel(string id, TeacherPositionType position, string userid, DateTime dateHiring) : IValidation
{
public string Id { get; private set; } = id;
public string Userid { get; private set; } = userid;
public string UserId { get; private set; } = userid;
public TeacherPositionType Position { get; set; } = position;
public DateTime DateHiring { get; private set; } = dateHiring;
@@ -27,10 +27,10 @@ public class TeacherDataModel(string id, TeacherPositionType position, string us
if (!Id.IsGuid())
throw new ValidationException("Teacher ID must be a valid GUID");
if (Userid.IsEmpty())
if (UserId.IsEmpty())
throw new ValidationException("User ID cannot be empty");
if (!Userid.IsGuid())
if (!UserId.IsGuid())
throw new ValidationException("User ID must be a valid GUID");
if (Position == TeacherPositionType.None)

View File

@@ -0,0 +1,8 @@
namespace UniversityAllExpelled_Models.Exceptions;
public class DuplicateEmployeeException : Exception
{
public DuplicateEmployeeException(string id)
: base($"Employee with ID {id} already exists") { }
}

View File

@@ -8,4 +8,5 @@ namespace UniversityAllExpelled_Models.Exceptions;
public class NullListException : Exception
{
public NullListException() : base("The returned list is null") { }
}

View File

@@ -9,6 +9,7 @@ namespace UniversityAllExpelled_Models.StorageContracts
List<EducationDataModel>? GetListByTeacherId(string teacherId);
List<EducationDataModel>? GetListByActive(bool active);
List<EducationDataModel>? GetListByDateRange(DateTime startDate, DateTime endDate);
public List<EducationDataModel> GetAllEducationByLessons();
void AddElement(EducationDataModel educationDataModel);
void UpdElement(EducationDataModel educationDataModel);
void DelElement(EducationDataModel educationDataModel);

View File

@@ -13,4 +13,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="UniversityAllExpelled_WebApi" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
using UniversityAllExpelled_Models.Enums; // Подключи свой namespace с enum
namespace YourNamespace.Controllers
{
[ApiController]
[Route("api/enums")]
public class EnumsController : ControllerBase
{
[HttpGet("faculties")]
public IActionResult GetFaculties()
{
var faculties = Enum.GetValues(typeof(FacultyType))
.Cast<FacultyType>()
.Select(f => new { id = (int)f, name = f.ToString() })
.ToList();
return Ok(faculties);
}
[HttpGet("groups")]
public IActionResult GetGroups()
{
var groups = Enum.GetValues(typeof(GroopType))
.Cast<GroopType>()
.Select(g => new { id = (int)g, name = g.ToString() })
.ToList();
return Ok(groups);
}
[HttpGet("positions")]
public IActionResult GetPositions()
{
var positions = Enum.GetValues(typeof(TeacherPositionType))
.Cast<TeacherPositionType>()
.Select(p => new { id = (int)p, name = p.ToString() })
.ToList();
return Ok(positions);
}
// Если нужно, добавьте курсы и другие enum по аналогии
}
}

View File

@@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Mvc;
using UniversityAllExpelled_DataBase;
using UniversityAllExpelled_DataBase.Models;
using UniversityAllExpelled_Models.DTOs;
using UniversityAllExpelled_Models.Enums;
namespace UniversityAllExpelled_WebApi.Controllers;
[Route("api/register")]
[ApiController]
public class RegisterController : ControllerBase
{
private readonly IUniversityDbContext _context;
public RegisterController(IUniversityDbContext context)
{
_context = context;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
{
if (!ModelState.IsValid)
return BadRequest(new { message = "Некорректные данные" });
if (request.Password != request.ConfirmPassword)
return BadRequest(new { message = "Пароли не совпадают" });
if (_context.Users.Any(u => u.Login == request.Login))
return Conflict(new { message = "Пользователь с таким логином уже существует" });
var user = new User
{
Id = Guid.NewGuid().ToString(),
Login = request.Login,
Password = request.Password,
Email = request.Email,
FIO = request.FIO,
PhoneNomber = request.PhoneNomber,
BirthDate = request.BirthDate,
Role = Enum.TryParse<SystemRoleType>(request.Role, true, out var r) ? r : SystemRoleType.None,
IsDeleted = false
};
_context.Users.Add(user);
if (user.Role == SystemRoleType.student)
{
if (!Enum.TryParse<FacultyType>(request.Faculty, true, out var faculty) ||
!Enum.TryParse<GroopType>(request.Groop, true, out var groop) || request.Course == null)
return BadRequest(new { message = "Неверные параметры студента" });
var student = new Student(Guid.NewGuid().ToString(), user.Id, faculty, groop, request.Course.Value);
_context.Students.Add(student);
}
else if (user.Role == SystemRoleType.teacher)
{
if (!Enum.TryParse<TeacherPositionType>(request.Position, true, out var position) || request.DateHiring == null)
return BadRequest(new { message = "Неверные параметры преподавателя" });
var teacher = new Teacher(Guid.NewGuid().ToString(), position, user.Id, request.DateHiring.Value);
_context.Teachers.Add(teacher);
}
await _context.SaveChangesAsync();
return Ok(new { message = "Регистрация успешна" });
}
}

View File

@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using UniversityAllExpelled_DataBase;
namespace UniversityAllExpelled_WebApi.Controllers;
[Route("api/student")]
[ApiController]
public class StudentController : ControllerBase
{
private readonly IUniversityDbContext _context;
public StudentController(IUniversityDbContext context)
{
_context = context;
}
[HttpGet("data")]
[Authorize(Roles = "student")]
public IActionResult GetStudentData()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
var student = _context.Students.FirstOrDefault(s => s.UserId == userId);
if (student == null) return NotFound();
return Ok(new
{
faculty = student.Faculty.ToString(),
groop = student.Groop.ToString(),
course = student.Course
});
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using UniversityAllExpelled_DataBase;
namespace UniversityAllExpelled_WebApi.Controllers;
[Route("api/teacher")]
[ApiController]
public class TeacherController : ControllerBase
{
private readonly IUniversityDbContext _context;
public TeacherController(IUniversityDbContext context)
{
_context = context;
}
[HttpGet("data")]
[Authorize(Roles = "teacher")]
public IActionResult GetTeacherData()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
var teacher = _context.Teachers.FirstOrDefault(t => t.UserId == userId);
if (teacher == null) return NotFound();
return Ok(new
{
position = teacher.Position.ToString(),
dateHiring = teacher.DateHiring
});
}
}

View File

@@ -0,0 +1,84 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using UniversityAllExpelled_DataBase;
using UniversityAllExpelled_DataBase.Models;
using UniversityAllExpelled_Models.DTOs;
using UniversityAllExpelled_WebApi.Services;
namespace UniversityAllExpelled_WebApi.Controllers;
[ApiController]
[Route("api/user")]
public class UserController : ControllerBase
{
private readonly IUniversityDbContext _context;
private readonly ITokenService _tokenService;
public UserController(IUniversityDbContext context, ITokenService tokenService)
{
_context = context;
_tokenService = tokenService;
}
/// <summary>
/// Авторизация пользователя
/// </summary>
[HttpPost("login")]
public IActionResult Login([FromBody] LoginRequest request)
{
if (string.IsNullOrWhiteSpace(request.Login) || string.IsNullOrWhiteSpace(request.Password))
return BadRequest(new { message = "Поля логина и пароля обязательны" });
var user = _context.Users
.FirstOrDefault(u => u.Login == request.Login && u.Password == request.Password && !u.IsDeleted);
if (user == null)
return Unauthorized(new { message = "Неверный логин или пароль" });
var token = _tokenService.GenerateToken(user);
return Ok(new
{
access_token = token,
user = new
{
id = user.Id,
fio = user.FIO,
email = user.Email,
login = user.Login,
phoneNomber = user.PhoneNomber,
birthDate = user.BirthDate,
role = user.Role.ToString().ToLower()
}
});
}
/// <summary>
/// Получить профиль текущего пользователя
/// </summary>
[HttpGet("profile")]
[Authorize]
public IActionResult GetProfile()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId))
return Unauthorized();
var user = _context.Users.FirstOrDefault(u => u.Id == userId);
if (user == null)
return NotFound();
return Ok(new
{
id = user.Id,
fio = user.FIO,
email = user.Email,
login = user.Login,
phoneNomber = user.PhoneNomber,
birthDate = user.BirthDate,
role = user.Role.ToString().ToLower()
});
}
}

View File

@@ -0,0 +1,21 @@
using UniversityAllExpelled_Models.Infrostructure;
namespace UniversityAllExpelled_WebApi.Infrastructure;
public class ConfigurationDatabase : IConfigurationDatabase
{
//private readonly Lazy<DataBaseSettings> _dataBaseSettings = new(() =>
//{
// return configuration.GetValue<DataBaseSettings>("DataBaseSettings") ?? throw new InvalidDataException(nameof(DataBaseSettings));
//});
//public string ConnectionString => _dataBaseSettings.Value.ConnectionString;
private readonly string _connectionString;
public ConfigurationDatabase(IConfiguration configuration)
{
_connectionString = configuration["DataBaseSettings:ConnectionString"] ?? throw new InvalidDataException("DataBaseSettings:ConnectionString не найден в конфигурации");
}
public string ConnectionString => _connectionString;
}

View File

@@ -0,0 +1,7 @@
namespace UniversityAllExpelled_WebApi.Infrastructure;
public class DataBaseSettings
{
public required string ConnectionString { get; set; }
}

View File

@@ -0,0 +1,96 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using UniversityAllExpelled_BusinessLogic.Implementations;
using UniversityAllExpelled_DataBase;
using UniversityAllExpelled_DataBase.Implementations;
using UniversityAllExpelled_Models.BusinessLogicContracts;
using UniversityAllExpelled_Models.DataModels;
using UniversityAllExpelled_Models.Infrostructure;
using UniversityAllExpelled_Models.StorageContracts;
using UniversityAllExpelled_WebApi.Infrastructure;
using UniversityAllExpelled_WebApi.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllers();
builder.Services.AddLogging();
builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = AuthOptions.ISSUER,
ValidateAudience = true,
ValidAudience = AuthOptions.AUDIENCE,
ValidateLifetime = true,
IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
ValidateIssuerSigningKey = true,
};
});
builder.Services.AddSingleton<IConfigurationDatabase, ConfigurationDatabase>();
builder.Services.AddTransient<IUserBusinessLogicContract, UserBusinessLogicContract>();
builder.Services.AddTransient<IStudentBusinessLogicContract, StudentBusinessLogicContract>();
builder.Services.AddTransient<ITeacherBusinessLogicContract, TeacherBusinessLogicContract>();
builder.Services.AddTransient<ILessonBusinessLogicContract, LessonBusinessLogicContract>();
builder.Services.AddTransient<ISalaryBusinessLogicContract, SalaryBusinessLogicContract>();
builder.Services.AddTransient<IEducationBusinessLogicContract, EducationBusinessLogicContract>();
builder.Services.AddTransient<IEducationLessonsBusinessLogicContract, EducationLessonsBusinessLogicContract>();
builder.Services.AddTransient<IPaymentBusinessLogicContract, PaymentBusinessLogicContract>();
builder.Services.AddScoped<IUniversityDbContext, UniversityAllExpelledDbContext>();
builder.Services.AddDbContext<UniversityAllExpelledDbContext>(options =>
options.UseNpgsql(
builder.Configuration["DataBaseSettings:ConnectionString"],
x => x.MigrationsAssembly("UniversityAllExpelled_WebApi")
));
builder.Services.AddTransient<IUserStorageContract, UserStorageContract>();
builder.Services.AddTransient<IStudentStorageContract, StudentStorageContract>();
builder.Services.AddTransient<ITeacherStorageContract, TeacherStorageContract>();
builder.Services.AddTransient<ILessonStorageContract, LessonStorageContract>();
builder.Services.AddTransient<ISalaryStorageContract, SalaryStorageContract>();
builder.Services.AddTransient<IEducationStorageContract, EducationStorageContract>();
builder.Services.AddTransient<IEducationLessonsStorageContract, EducationLessonsStorageContract>();
builder.Services.AddTransient<IPaymentStorageContract, PaymentStorageContract>();
builder.Services.AddTransient<ITokenService, TokenService>();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapControllers();
app.UseDefaultFiles();
app.UseStaticFiles(); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> wwwroot
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
});
public class AuthOptions
{
public const string ISSUER = "MyAuthServer";
public const string AUDIENCE = "MyAuthClient";
const string KEY = "mysupersecret_secretsecretsecretkey!123";
public static SymmetricSecurityKey GetSymmetricSecurityKey() =>
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(KEY));
}

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5215",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7226;http://localhost:5215",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using UniversityAllExpelled_DataBase.Models;
using UniversityAllExpelled_WebApi.Infrastructure;
namespace UniversityAllExpelled_WebApi.Services;
public interface ITokenService
{
string GenerateToken(User user);
}
public class TokenService : ITokenService
{
public string GenerateToken(User user)
{
var claims = new List<Claim>
{
new(ClaimTypes.NameIdentifier, user.Id), // Это ключевой клейм, используется как "user id"
new(ClaimTypes.Name, user.Login),
new(ClaimTypes.Role, user.Role.ToString().ToLower())
};
var jwt = new JwtSecurityToken(
issuer: AuthOptions.ISSUER,
audience: AuthOptions.AUDIENCE,
claims: claims,
expires: DateTime.UtcNow.AddHours(6),
signingCredentials: new SigningCredentials(
AuthOptions.GetSymmetricSecurityKey(),
SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
}

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.10.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UniversityAllExpelled_BusinessLogic\UniversityAllExpelled_BusinessLogic.csproj" />
<ProjectReference Include="..\UniversityAllExpelled_DataBase\UniversityAllExpelled_DataBase.csproj" />
<ProjectReference Include="..\UniversityAllExpelled_Models\UniversityAllExpelled_Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
@UniversityAllExpelled_WebApi_HostAddress = http://localhost:5215
GET {{UniversityAllExpelled_WebApi_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"DataBaseSettings": {
"ConnectionString": "Host=localhost;Port=5432;Database=university;Username=postgres"
}
}

View File

@@ -0,0 +1,61 @@
<!-- createEduLes.html -->
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Создание урока</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/edu-create.css" rel="stylesheet">
</head>
<body>
<div class="dashboard-layout">
<!-- Боковая панель -->
<aside class="sidebar">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo">
</div>
<button class="back-button" onclick="location.href='/mainLK.html'">&larr; Назад</button>
</aside>
<!-- Основной контент -->
<main class="form-content">
<h1>Создание предмета</h1>
<form id="lessonForm">
<div class="form-group">
<label for="lessonTitle">Название предмета</label>
<input type="text" class="form-control" id="lessonTitle" placeholder="Введите название" required>
</div>
<div class="form-group">
<label for="lessonDescription">Описание</label>
<textarea class="form-control" id="lessonDescription" rows="4" placeholder="Введите описание"></textarea>
</div>
<div class="form-group">
<label for="lessonDate">Дата проведения</label>
<input type="date" class="form-control" id="lessonDate" required>
</div>
<div class="form-group">
<label for="lessonTime">Время</label>
<input type="time" class="form-control" id="lessonTime" required>
</div>
<div class="form-group">
<label for="lessonGroup">Группа</label>
<select id="lessonGroup" class="form-control">
<option value="">Выберите группу</option>
<option value="PIbd-31">ПИбд-31</option>
<option value="PIbd-32">ПИбд-32</option>
<!-- можно добавить динамически -->
</select>
</div>
<button type="submit" class="btn btn-primary">Создать предмет</button>
</form>
</main>
</div>
</body>
</html>

View File

@@ -0,0 +1,55 @@
<!-- createStudentTraining.html -->
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Создание обучения</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/css/edu-create.css">
</head>
<body>
<div class="dashboard-layout">
<!-- Боковая панель -->
<aside class="sidebar">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo">
</div>
<button class="back-button" onclick="location.href='/mainLK.html'">&larr; Назад</button>
</aside>
<!-- Основной контент -->
<main class="form-content">
<h1>Создание обучения</h1>
<form id="trainingForm">
<div class="form-group">
<label for="trainingTitle">Название курса</label>
<input type="text" class="form-control" id="trainingTitle" placeholder="Например, JavaScript для начинающих" required>
</div>
<div class="form-group">
<label for="trainingType">Тип курса</label>
<select id="trainingType" class="form-control" required>
<option value="">Выберите направление</option>
<option value="it">IT</option>
<option value="design">Дизайн</option>
<option value="business">Бизнес</option>
</select>
</div>
<div class="form-group">
<label for="trainingGoal">Цель обучения</label>
<textarea class="form-control" id="trainingGoal" rows="3" placeholder="Например, освоить основы JS"></textarea>
</div>
<div class="form-group">
<label for="preferredTeacher">Желаемый преподаватель</label>
<input type="text" class="form-control" id="preferredTeacher" placeholder="ФИО (по желанию)">
</div>
<button type="submit" class="btn btn-success">Отправить заявку</button>
</form>
</main>
</div>
</body>
</html>

View File

@@ -0,0 +1,191 @@
/* Общие стили */
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
height: 100%;
background: linear-gradient(to right, #a2d4f1, #00c6d7);
color: #333333;
}
/* Основная сетка */
.dashboard-layout {
display: flex;
height: 100vh;
}
/* Боковая панель */
.sidebar {
width: 250px;
background: rgba(255, 255, 255, 0.3);
border-right: 2px solid #00BFFF;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 10px;
box-sizing: border-box;
overflow: auto;
color: #333333;
}
/* Контейнер логотипа */
.logo-section {
margin-bottom: 30px;
width: 100%;
display: flex;
justify-content: center;
}
/* Сам логотип */
.main-logo {
max-width: 100%;
height: auto;
max-height: 120px;
object-fit: contain;
}
/* Контейнер кнопок */
.nav-container {
display: flex;
flex-direction: column;
gap: 20px;
width: 100%;
align-items: center;
}
/* Кнопки навигации */
.nav-button {
width: 80%;
padding: 12px 20px;
background-color: rgba(0, 0, 0, 0.2);
border: 2px solid #00BFFF;
color: #333333;
font-size: 16px;
font-weight: 500;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.nav-button:hover {
background-color: rgba(0, 0, 0, 0.35);
}
/* Основной блок информации */
main,
.student-info {
flex: 1;
padding: 40px;
color: #333333;
display: flex;
flex-direction: column;
justify-content: flex-start;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(4px);
overflow-y: auto;
}
.student-info h1,
main h1 {
margin-bottom: 30px;
font-size: 28px;
color: #333333;
}
.info-group p {
font-size: 16px;
margin: 10px 0;
color: #333333;
}
/* Кнопки действий преподавателя и форм */
.action-group {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 30px;
}
.action-group button,
form button {
padding: 10px 20px;
border-radius: 10px;
border: 2px solid #00BFFF;
background-color: rgba(0, 0, 0, 0.2);
color: #333333;
font-size: 15px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s ease;
}
.action-group button:hover,
form button:hover {
background-color: rgba(0, 0, 0, 0.35);
}
/* Формы */
form {
max-width: 600px;
margin-top: 20px;
background: rgba(255, 255, 255, 0.2);
padding: 20px;
border-radius: 12px;
box-shadow: 0 0 10px rgba(0, 191, 255, 0.4);
color: #333333;
}
.form-group {
margin-bottom: 15px;
}
form label {
font-weight: bold;
display: block;
margin-bottom: 6px;
color: #333333;
}
form input,
form select,
form textarea {
width: 100%;
padding: 10px;
border-radius: 8px;
border: 1px solid #00BFFF;
background-color: rgba(255, 255, 255, 0.2);
color: #333333;
font-size: 14px;
box-sizing: border-box;
}
form input:focus,
form select:focus,
form textarea:focus {
outline: none;
background-color: rgba(255, 255, 255, 0.3);
}
/* Адаптивность */
@media (max-width: 768px) {
.dashboard-layout {
flex-direction: column;
}
.sidebar {
width: 100%;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
}
.nav-button {
width: 40%;
margin: 10px 5px;
}
main,
.student-info {
padding: 20px;
}
}

View File

@@ -0,0 +1,219 @@
/* Общие стили */
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
height: 100%;
background: linear-gradient(to right, #a2d4f1, #00c6d7);
}
/* Основная сетка */
.dashboard-layout {
display: flex;
height: 100vh;
}
/* Боковая панель */
.sidebar {
width: 250px;
background: rgba(255, 255, 255, 0.3);
border-right: 2px solid #00BFFF;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 10px;
box-sizing: border-box;
overflow: auto;
}
/* Контейнер логотипа */
.logo-section {
margin-bottom: 30px;
width: 100%;
display: flex;
justify-content: center;
}
/* Сам логотип */
.main-logo {
max-width: 100%;
height: auto;
max-height: 120px;
object-fit: contain;
}
/* Контейнер кнопок */
.nav-container {
display: flex;
flex-direction: column;
gap: 20px;
width: 100%;
align-items: center;
}
/* Кнопки навигации */
.nav-button {
width: 80%;
padding: 12px 20px;
background-color: rgba(0, 0, 0, 0.2);
border: 2px solid #00BFFF;
color: #fff;
font-size: 16px;
font-weight: 500;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.nav-button:hover {
background-color: rgba(0, 0, 0, 0.35);
}
/* Основной блок информации */
.student-info {
flex: 1;
padding: 40px;
color: #fff;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.student-info h1 {
margin-bottom: 30px;
font-size: 28px;
color: #ffffff;
}
.info-group p {
font-size: 16px;
margin: 10px 0;
}
.dashboard-layout {
display: flex;
height: 100vh;
background-color: #f8f9fa;
}
.sidebar {
width: 280px;
background: linear-gradient(to bottom, #2c3e50, #3498db);
color: white;
padding: 20px;
display: flex;
flex-direction: column;
}
.logo-section {
text-align: center;
padding: 20px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.main-logo {
max-width: 180px;
height: auto;
}
.user-info {
padding: 20px 0;
text-align: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.user-info h4 {
margin: 0;
font-size: 1.2rem;
}
.user-info p {
margin: 5px 0 0;
color: #ecf0f1;
font-size: 0.9rem;
}
.nav-container {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px;
}
.nav-button {
padding: 12px 15px;
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 6px;
color: white;
text-align: left;
cursor: pointer;
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease;
}
.nav-button:hover {
background: rgba(255, 255, 255, 0.2);
}
.nav-button.active {
background: rgba(255, 255, 255, 0.3);
font-weight: bold;
}
.nav-button i {
font-size: 1.1rem;
}
.student-info {
flex: 1;
padding: 30px;
overflow-y: auto;
}
.content-section {
background: white;
border-radius: 8px;
padding: 25px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
margin-bottom: 20px;
}
.info-group p {
margin: 12px 0;
font-size: 1rem;
color: #333;
}
.info-group strong {
color: #2c3e50;
min-width: 120px;
display: inline-block;
}
/* Адаптивность */
@media (max-width: 768px) {
.dashboard-layout {
flex-direction: column;
}
.sidebar {
width: 100%;
padding: 15px;
}
.nav-container {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.nav-button {
flex: 1 1 150px;
justify-content: center;
}
.student-info {
padding: 20px;
}
}

View File

@@ -0,0 +1,159 @@
/* Общие стили */
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
height: 100%;
background: linear-gradient(to right, #a2d4f1, #00c6d7);
}
/* Разметка */
.payment-layout {
display: flex;
min-height: 100vh
}
/* Боковая панель */
.sidebar {
height: auto;
min-height: 100%;
width: 150px;
background: rgba(255, 255, 255, 0.1);
border-right: 1px solid #00BFFF;
display: flex;
flex-direction: column; /* изменено: вертикальное расположение */
align-items: center;
padding: 20px 10px;
box-sizing: border-box;
}
/* Секция логотипа */
.logo-section {
width: 100%;
display: flex;
justify-content: center;
margin-bottom: 20px; /* отступ от логотипа до кнопки */
}
.main-logo {
max-width: 100%;
max-height: 60px;
object-fit: contain;
}
/* Кнопка "На Главную" */
.back-button {
padding: 10px;
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
border: 2px solid #003344;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
text-align: center;
margin-bottom: 20px;
}
.back-button:hover {
background-color: rgba(0, 0, 0, 0.4);
}
/* Контент */
.payment-content {
flex: 1;
padding: 40px;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
}
/* Заголовок */
.section-title {
font-size: 28px;
margin-bottom: 30px;
}
/* Информация по оплате */
.payment-info-box {
background: rgba(255, 255, 255, 0.2);
padding: 25px 20px;
border-radius: 10px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
margin-bottom: 25px;
width: 100%;
max-width: 450px;
}
.payment-info-box p {
margin: 10px 0;
}
/* Элементы ввода */
.payment-input {
padding: 10px;
font-size: 14px;
margin-top: 10px;
border: none;
border-radius: 6px;
width: 100%;
box-sizing: border-box;
}
/* Кнопка оплаты */
.pay-button {
padding: 12px;
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
border: 2px solid #003344;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
max-width: 450px;
}
.pay-button:hover {
background-color: rgba(0, 0, 0, 0.4);
}
/* Форма оплаты */
.payment-form {
background: rgba(255, 255, 255, 0.2);
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 450px;
display: flex;
flex-direction: column;
gap: 15px;
}
/* Детали карты */
#cardDetails {
display: none;
flex-direction: column;
gap: 15px;
}
/* Номер карты — отдельной строкой */
#cardNumber {
width: 100%;
}
/* MM/YY и CSV — в строку */
.card-row {
display: flex;
gap: 15px;
}
#cardExpiry,
#cardCSV {
flex: 1;
min-width: 0;
}

View File

@@ -0,0 +1,145 @@
/* Общие стили */
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
height: 100%;
background: linear-gradient(to right, #a2d4f1, #00c6d7);
}
/* Основная раскладка */
.reports-layout {
display: flex;
height: 100vh;
}
/* Боковая панель */
.sidebar {
width: 80px;
background: rgba(255, 255, 255, 0.1);
border-right: 2px solid #003344;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
box-sizing: border-box;
}
.logo-section {
width: 100%;
display: flex;
justify-content: center;
}
.main-logo {
max-width: 100%;
max-height: 60px;
object-fit: contain;
}
/* Контентная область */
.reports-content {
flex: 1;
padding: 40px;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
}
.section-title {
font-size: 28px;
margin-bottom: 40px;
}
/* Интерфейс генерации отчета */
.report-interface {
background: rgba(255, 255, 255, 0.2);
padding: 30px 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
gap: 15px;
width: 100%;
max-width: 480px;
align-items: stretch;
}
/* Поля выбора */
.report-select {
padding: 10px;
font-size: 14px;
border: none;
border-radius: 6px;
width: 100%;
box-sizing: border-box;
}
/* Ряд с двумя полями даты */
.date-range {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
}
.date-range label {
color: #fff;
font-size: 14px;
white-space: nowrap;
}
.report-input {
padding: 10px;
font-size: 14px;
border: none;
border-radius: 6px;
width: 48%; /* Уменьшено до ~половины родителя */
box-sizing: border-box;
}
/* Кнопка "Сформировать отчет" */
.generate-button {
padding: 10px;
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
border: 2px solid #003344;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
box-sizing: border-box;
}
.generate-button:hover {
background-color: rgba(0, 0, 0, 0.4);
}
/* Контейнер кнопок форматов */
.format-buttons {
display: none; /* Скрыт по умолчанию */
justify-content: space-between;
gap: 5px;
margin-top: 10px;
width: 100%;
}
/* Кнопки форматов */
.format-option {
width: 32%;
padding: 10px;
background-color: rgba(0, 0, 0, 0.2);
color: #fff;
border: 2px solid #003344;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
box-sizing: border-box;
}
.format-option:hover {
background-color: rgba(0, 0, 0, 0.4);
}

View File

@@ -0,0 +1,179 @@
/* Общие базовые настройки */
* {
box-sizing: border-box;
}
body, html {
margin: 0;
padding: 0;
height: 100%;
font-family: Arial, sans-serif;
background: linear-gradient(to right, #a2d4f1, #00c6d7);
}
/* Контейнер всей страницы с двумя колонками */
.page-layout {
display: flex;
height: 100vh;
}
/* Левая часть — логотип */
.logo-section {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.main-logo {
max-width: 80%;
height: auto;
}
/* Правая часть — форма авторизации/регистрации */
.auth-container {
width: 300px;
background: rgba(255, 255, 255, 0.2);
border-left: 2px solid #fff;
padding: 50px 40px;
display: flex;
flex-direction: column;
min-height: 130vh;
box-sizing: border-box;
overflow-y: auto;
}
/* Контейнер формы */
.auth-box {
display: flex;
flex-direction: column;
width: 100%;
min-height: 130vh;
}
/* Заголовок формы */
.auth-box h2 {
text-align: center;
color: #fff;
margin-bottom: 25px;
}
/* Форма — вертикальный стек элементов */
.auth-form {
display: flex;
flex-direction: column;
width: 100%;
}
/* Универсальный стиль для всех input и select */
.auth-input {
width: 100%;
padding: 8px 10px;
border-radius: 6px;
border: none;
font-size: 14px;
margin-bottom: 10px; /* Интервал 10px между всеми полями */
background-color: rgba(255, 255, 255, 0.9);
color: #000;
box-sizing: border-box;
transition: box-shadow 0.3s ease;
}
.auth-input:focus {
outline: none;
box-shadow: 0 0 5px 2px #00c6d7;
}
/* Свитч роли — вертикальный стек радио */
.role-switch {
display: flex;
flex-direction: column; /* вертикально */
color: #fff;
font-size: 14px;
margin-bottom: 10px; /* 10px отступ */
}
.role-switch label {
display: flex;
align-items: center;
cursor: pointer;
margin-bottom: 10px; /* интервал между радио */
}
.role-switch input[type="radio"] {
width: 16px;
height: 16px;
margin-right: 8px;
vertical-align: middle;
}
/* Контейнер для дополнительных полей */
.additional-fields {
display: flex;
flex-direction: column;
margin-bottom: 10px; /* 10px между блоками */
}
/* Подвал формы с кнопкой */
.auth-footer {
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 10px;
}
/* Кнопка отправки */
.login-btn {
padding: 8px 20px;
font-size: 14px;
border-radius: 6px;
cursor: pointer;
background-color: #00c6d7;
border: none;
color: white;
transition: background-color 0.3s ease;
}
.login-btn:hover {
background-color: #009ba0;
}
/* Добавляем стили для сообщения об ошибке */
.alert-danger {
background-color: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
/* Анимация для кнопки входа */
.login-btn {
transition: all 0.3s ease;
}
.login-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
/* Адаптивность для мобильных устройств */
@media (max-width: 768px) {
.page-layout {
flex-direction: column;
}
.logo-section {
padding: 1rem;
}
.auth-container {
width: 100%;
padding: 1.5rem;
}
.auth-box {
padding: 1rem;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>УГУ - Вход в систему</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/site.css" rel="stylesheet">
</head>
<body>
<div class="page-layout">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип УГУ" class="main-logo">
</div>
<div class="auth-container">
<div class="auth-box">
<h2>Вход</h2>
<form id="loginForm">
<div id="errorMessage" class="alert alert-danger d-none"></div>
<input type="text" id="loginInput" class="auth-input" placeholder="Логин" required>
<input type="password" id="passwordInput" class="auth-input" placeholder="Пароль" required>
<div class="auth-footer">
<a href="/register.html" class="register-link">Регистрация</a>
<button type="submit" class="btn btn-primary login-btn">Войти</button>
</div>
</form>
</div>
</div>
</div>
<script type="module" src="/js/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,23 @@
export function getAuthHeaders(token) {
return {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
export async function fetchWithToken(url, token, options = {}) {
const res = await fetch(url, {
...options,
headers: {
...getAuthHeaders(token),
...(options.headers || {})
}
});
if (!res.ok) {
const error = await res.json().catch(() => ({}));
throw new Error(error.message || res.statusText);
}
return await res.json();
}

View File

@@ -0,0 +1,54 @@
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('loginForm');
const loginInput = document.getElementById('loginInput');
const passwordInput = document.getElementById('passwordInput');
const errorMessage = document.getElementById('errorMessage');
const submitBtn = form.querySelector('button[type="submit"]');
if (localStorage.getItem('authToken') && localStorage.getItem('userData')) {
const user = JSON.parse(localStorage.getItem('userData'));
redirectByRole(user.role);
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
const login = loginInput.value.trim();
const password = passwordInput.value.trim();
if (!login || !password) return showError('Введите логин и пароль');
try {
submitBtn.disabled = true;
submitBtn.innerHTML = `Вход...`;
const res = await fetch('/api/user/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ login, password })
});
const data = await res.json();
if (!res.ok) throw new Error(data.message);
localStorage.setItem('authToken', data.access_token);
localStorage.setItem('userData', JSON.stringify(data.user));
redirectByRole(data.user.role);
} catch (err) {
showError(err.message || 'Ошибка авторизации');
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Войти';
}
});
function showError(msg) {
errorMessage.textContent = msg;
errorMessage.classList.remove('d-none');
}
function redirectByRole(role) {
window.location.href = '/mainLK.html';
}
});

View File

@@ -0,0 +1,20 @@
import { setupRegisterForm } from './register.js';
import { setupLoginForm } from './auth.js';
import { loadProfile } from './profile.js';
import { setupLkNavigation } from './lk.js';
/**
* Определяет текущую страницу и запускает соответствующую инициализацию.
*/
document.addEventListener('DOMContentLoaded', () => {
const path = window.location.pathname;
if (path.endsWith('/register.html')) {
setupRegisterForm();
} else if (path.endsWith('/index.html') || path === '/') {
setupLoginForm();
} else if (path.endsWith('/mainLK.html')) {
loadProfile();
setupLkNavigation();
}
});

View File

@@ -0,0 +1,37 @@
document.addEventListener("DOMContentLoaded", function () {
const payButton = document.getElementById("payButton");
const paymentForm = document.getElementById("paymentForm");
const paymentMethod = document.getElementById("paymentMethod");
const cardDetails = document.getElementById("cardDetails");
const amountInput = document.getElementById("amount");
const cardNumberInput = document.getElementById("cardNumber");
const cardExpiryInput = document.getElementById("cardExpiry");
const cardCSVInput = document.getElementById("cardCSV");
// Показываем форму оплаты
payButton.addEventListener("click", function () {
if (paymentForm.style.display === "none") {
paymentForm.style.display = "flex";
} else {
// Очистка всех полей
amountInput.value = "";
paymentMethod.value = "";
cardNumberInput.value = "";
cardExpiryInput.value = "";
cardCSVInput.value = "";
cardDetails.style.display = "none";
paymentForm.style.display = "none";
}
});
// Обработка изменения способа оплаты
paymentMethod.addEventListener("change", function () {
if (paymentMethod.value === "card") {
cardDetails.style.display = "flex";
} else {
cardDetails.style.display = "none";
}
});
});

View File

@@ -0,0 +1,16 @@
import { fetchWithToken } from './api.js';
document.addEventListener('DOMContentLoaded', async () => {
const token = localStorage.getItem('authToken');
if (!token) return window.location.href = '/index.html';
try {
const user = await fetchWithToken('/api/user/profile', token);
document.getElementById('userName').textContent = user.fio;
document.getElementById('userRole').textContent = user.role;
document.getElementById('userEmail').textContent = user.email;
document.getElementById('userPhone').textContent = user.phoneNomber;
} catch (err) {
alert('Ошибка профиля');
}
});

View File

@@ -0,0 +1,51 @@
import { validateForm } from './validation.js';
import { toggleRoleFields, loadEnums } from './roles.js';
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('registerForm');
form.addEventListener('submit', async (e) => {
e.preventDefault();
if (!validateForm(form)) return;
const formData = new FormData(form);
const data = {
FIO: formData.get('fio'),
Login: formData.get('login'),
Email: formData.get('email'),
PhoneNomber: formData.get('phoneNomber'),
BirthDate: new Date(formData.get('birthDate')).toISOString(),
Password: formData.get('password'),
ConfirmPassword: formData.get('confirmPassword'),
Role: formData.get('role'),
Faculty: formData.get('faculty'),
Groop: formData.get('groop'),
Course: parseInt(formData.get('course')),
Position: formData.get('position'),
DateHiring: formData.get('dateHiring') ? new Date(formData.get('dateHiring')).toISOString() : null
};
try {
const res = await fetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!res.ok) {
const error = await res.json().catch(() => ({ message: 'Ошибка регистрации' }));
alert(error.message);
return;
}
alert('Регистрация прошла успешно!');
window.location.href = '/index.html';
} catch (err) {
alert('Ошибка подключения к серверу');
console.error(err);
}
});
toggleRoleFields();
loadEnums();
});

View File

@@ -0,0 +1,20 @@
document.addEventListener('DOMContentLoaded', function () {
const generateButton = document.getElementById('generateReport');
const formatButtons = document.getElementById('formatButtons');
const reportType = document.getElementById('reportType');
const dateFrom = document.getElementById('dateFrom');
const dateTo = document.getElementById('dateTo');
// Показать кнопки форматов при нажатии
generateButton.addEventListener('click', () => {
formatButtons.style.display = 'flex';
});
// Скрыть кнопки форматов при изменении любого поля
[reportType, dateFrom, dateTo].forEach(element => {
element.addEventListener('input', () => {
formatButtons.style.display = 'none';
});
});
});

View File

@@ -0,0 +1,44 @@
export function toggleRoleFields() {
const form = document.getElementById('registerForm');
const studentFields = document.getElementById('studentFields');
const teacherFields = document.getElementById('teacherFields');
const update = () => {
const role = form.role.value;
if (role === 'student') {
studentFields.style.display = 'flex';
teacherFields.style.display = 'none';
} else {
studentFields.style.display = 'none';
teacherFields.style.display = 'flex';
}
};
form.querySelectorAll('input[name="role"]').forEach(r => {
r.addEventListener('change', update);
});
update();
}
export async function loadEnums() {
await loadOptions('/api/enums/faculties', document.getElementById('facultySelect'));
await loadOptions('/api/enums/groups', document.getElementById('groupSelect'));
await loadOptions('/api/enums/positions', document.getElementById('positionSelect'));
}
async function loadOptions(url, select) {
try {
const res = await fetch(url);
const data = await res.json();
select.innerHTML = '<option disabled selected>Выберите...</option>';
data.forEach(d => {
const option = document.createElement('option');
option.value = d.name || d.id;
option.textContent = d.name;
select.appendChild(option);
});
} catch (err) {
alert(`Ошибка загрузки ${url}`);
}
}

View File

@@ -0,0 +1,39 @@
export function validateForm(form) {
const data = new FormData(form);
const password = data.get('password');
const confirmPassword = data.get('confirmPassword');
const email = data.get('email');
const phone = data.get('phoneNomber');
const birthDate = new Date(data.get('birthDate'));
const age = new Date().getFullYear() - birthDate.getFullYear();
if (password !== confirmPassword) {
alert('Пароли не совпадают!');
return false;
}
const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W).{8,}$/;
if (!passwordRegex.test(password)) {
alert('Слабый пароль');
return false;
}
const emailRegex = /^[\w.%+-]+@(gmail\.com|yandex\.[a-z]{2,}|mail\.ru|bk\.ru|inbox\.ru|list\.ru)$/;
if (!emailRegex.test(email)) {
alert('Неверный email');
return false;
}
const phoneRegex = /^(\+7|8)\d{10}$/;
if (!phoneRegex.test(phone)) {
alert('Неверный телефон');
return false;
}
if (age < 16) {
alert('Возраст должен быть от 16 лет');
return false;
}
return true;
}

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Личный кабинет</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/lk.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css" rel="stylesheet" />
</head>
<body>
<div class="dashboard-layout">
<!-- Боковая панель -->
<aside class="sidebar">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип УГУ" class="main-logo" />
</div>
<div class="user-info">
<h4 id="userName"></h4>
<p id="userRole"></p>
</div>
<div class="nav-container">
<button class="nav-button active" data-section="profile">
<i class="bi bi-person"></i> Профиль
</button>
<!-- Для студентов -->
<button class="nav-button" data-section="study" data-role="student">
<i class="bi bi-journal-bookmark"></i> Обучение
</button>
<button class="nav-button" data-section="payments" data-role="student">
<i class="bi bi-credit-card"></i> Оплата
</button>
<!-- Для преподавателей -->
<button class="nav-button" data-section="teaching" data-role="teacher">
<i class="bi bi-mortarboard"></i> Преподавание
</button>
<button class="nav-button" data-section="reports" data-role="teacher">
<i class="bi bi-graph-up"></i> Отчеты
</button>
<button class="nav-button" id="logoutBtn">
<i class="bi bi-box-arrow-right"></i> Выход
</button>
</div>
</aside>
<!-- Основной контент -->
<main class="student-info">
<!-- Секция профиля -->
<div id="profileSection" class="content-section">
<h1>Личный профиль</h1>
<div class="info-group">
<p><strong>ФИО:</strong> <span id="userFio"></span></p>
<p><strong>Email:</strong> <span id="userEmail"></span></p>
<p><strong>Телефон:</strong> <span id="userPhone"></span></p>
<!-- Для студентов -->
<div data-role="student">
<p><strong>Факультет:</strong> <span id="studentFaculty"></span></p>
<p><strong>Группа:</strong> <span id="studentGroup"></span></p>
<p><strong>Курс:</strong> <span id="studentCourse"></span></p>
</div>
<!-- Для преподавателей -->
<div data-role="teacher">
<p><strong>Должность:</strong> <span id="teacherPosition"></span></p>
<p><strong>Дата приема:</strong> <span id="teacherHireDate"></span></p>
<p><strong>Стаж:</strong> <span id="teacherExperience"></span></p>
</div>
</div>
</div>
<!-- Секции для студентов -->
<div id="studySection" class="content-section" style="display:none;" data-role="student">
<h2>Учебная информация</h2>
<div id="studyContent"></div>
</div>
<div id="paymentsSection" class="content-section" style="display:none;" data-role="student">
<h2>Финансовая информация</h2>
<div id="paymentsContent"></div>
</div>
<!-- Секции для преподавателей -->
<div id="teachingSection" class="content-section" style="display:none;" data-role="teacher">
<h2>Преподавательская деятельность</h2>
<div id="teachingContent"></div>
</div>
<div id="reportsSection" class="content-section" style="display:none;" data-role="teacher">
<h2>Отчеты и аналитика</h2>
<div id="reportsContent"></div>
</div>
</main>
</div>
<script type="module" src="/js/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Оплата обучения</title>
<link href="/css/payment.css" rel="stylesheet" />
</head>
<body>
<div class="payment-layout">
<!-- Боковая панель -->
<aside class="sidebar">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo" />
</div>
<button class="back-button" onclick="location.href='/mainLK.html'">&larr; На Главную</button>
</aside>
<!-- Основной контент -->
<main class="payment-content">
<h1 class="section-title">Оплата обучения</h1>
<div class="payment-info-box">
<p>
<strong>Обучение:</strong>
<select id="trainingSelect" class="payment-input" style="width: 100%; max-width: 400px; margin-bottom: 15px;">
<option value="" disabled selected>Выберите обучение</option>
<option value="programming">Программирование</option>
<option value="design">Дизайн</option>
<option value="marketing">Маркетинг</option>
</select>
</p>
<p><strong>Дата начала:</strong> <span id="startDate">none</span></p>
<p><strong>Дата окончания:</strong> <span id="endDate">none</span></p>
<p><strong>Цена:</strong> <span id="price">none</span></p>
<p><strong>Оплачено:</strong> <span id="paid">none</span></p>
<p><strong>Долг:</strong> <span id="debt">none</span></p>
</div>
<div id="paymentForm" class="payment-form" style="display: none;">
<input type="number" id="amount" class="payment-input" placeholder="Сумма" />
<select id="paymentMethod" class="payment-input">
<option value="" disabled selected>Выберите способ оплаты</option>
<option value="sbp">СБП</option>
<option value="card">По номеру карты</option>
</select>
<div id="cardDetails" style="display: none;">
<input type="text" class="payment-input" id="cardNumber" placeholder="Номер карты" />
<div class="card-row">
<input type="text" class="payment-input" id="cardExpiry" placeholder="MM/YY" />
<input type="text" class="payment-input" id="cardCSV" placeholder="CSV" />
</div>
</div>
</div>
<button id="payButton" class="pay-button">Оплатить</button>
</main>
</div>
<script src="/js/payment.js"></script>
</body>
</html>

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Регистрация — УГУво</title>
<link href="/css/bootstrap.min.css" rel="stylesheet" />
<link href="/css/site.css" rel="stylesheet" />
</head>
<body>
<div class="page-layout">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo" />
</div>
<div class="auth-container">
<div class="auth-box">
<h2>Регистрация</h2>
<form id="registerForm" class="auth-form" novalidate>
<div class="role-switch">
<label><input type="radio" name="role" value="student" checked /> Студент</label>
<label><input type="radio" name="role" value="teacher" /> Преподаватель</label>
</div>
<input type="text" name="fio" class="auth-input" placeholder="ФИО" required />
<input type="text" name="login" class="auth-input" placeholder="Логин" required />
<input type="email" name="email" class="auth-input" placeholder="Электронная почта" required />
<input type="tel" name="phoneNomber" class="auth-input" placeholder="Телефон" required />
<input type="date" name="birthDate" class="auth-input" placeholder="Дата рождения" required />
<input type="password" name="password" class="auth-input" placeholder="Пароль" required />
<input type="password" name="confirmPassword" class="auth-input" placeholder="Подтвердите пароль" required />
<div id="studentFields" class="additional-fields">
<select id="facultySelect" name="faculty" class="auth-input" required>
<option value="" disabled selected>Выберите факультет</option>
</select>
<select id="groupSelect" name="groop" class="auth-input" required>
<option value="" disabled selected>Выберите группу</option>
</select>
<input type="number" id="courseInput" name="course" class="auth-input" placeholder="Курс" min="1" max="6" required />
</div>
<div id="teacherFields" class="additional-fields" style="display:none;">
<select id="positionSelect" name="position" class="auth-input" required>
<option value="" disabled selected>Выберите должность</option>
</select>
<input type="date" name="dateHiring" class="auth-input" placeholder="Дата приема на работу" required />
</div>
<div class="auth-footer">
<button type="submit" class="btn btn-primary login-btn">Зарегистрироваться</button>
</div>
</form>
</div>
</div>
</div>
<script type="module" src="/js/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Отчёты</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/reports.css" rel="stylesheet">
</head>
<body>
<div class="reports-layout">
<!-- Боковая панель -->
<aside class="sidebar">
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo">
</div>
</aside>
<!-- Основной контент -->
<main class="reports-content">
<h1 class="section-title">Формирование отчетов</h1>
<div class="report-interface">
<label for="reportType">Выберите тип отчёта:</label>
<select id="reportType" class="report-select">
<option value="grades">Успеваемость</option>
<option value="payments">Оплаты</option>
<option value="attendance">Посещаемость</option>
</select>
<div class="date-range">
<label for="dateFrom">С:</label>
<input type="date" id="dateFrom" class="report-input">
<label for="dateTo">По:</label>
<input type="date" id="dateTo" class="report-input">
</div>
<button class="generate-button" id="generateReport">Сформировать отчёт</button>
<div class="format-buttons hidden" id="formatButtons">
<button class="generate-button format-option">.DOC</button>
<button class="generate-button format-option">.XLS</button>
<button class="generate-button format-option">.PDF</button>
</div>
</div>
</main>
</div>
<script src="/js/reports.js"></script>
</body>
</html>

View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Личный кабинет преподавателя</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/lk.css" rel="stylesheet"> <!-- можно переименовать в teacher.css при необходимости -->
</head>
<body>
<div class="dashboard-layout">
<!-- Боковая панель навигации -->
<aside class="sidebar">
<!-- Логотип -->
<div class="logo-section">
<img src="/image/logo.png" alt="Логотип" class="main-logo">
</div>
<!-- Кнопки навигации для преподавателя -->
<div class="nav-container">
<button class="nav-button">Дисциплины</button>
<button class="nav-button">Затраты</button>
<button class="nav-button">Отчеты</button>
<button class="nav-button">Экспорт</button>
<button class="nav-button">Сообщения</button>
</div>
</aside>
<!-- Основной контент -->
<main class="student-info">
<h1>Добро пожаловать, Елена Петрова</h1>
<div class="info-group">
<p><strong>ФИО:</strong> Петрова Елена Викторовна</p>
<p><strong>Email:</strong> petrova@example.com</p>
<p><strong>Телефон:</strong> +7 (900) 987-65-43</p>
<p><strong>Кафедра:</strong> Информационные системы</p>
<p><strong>Должность:</strong> Старший преподаватель</p>
</div>
<!-- Дополнительные действия преподавателя -->
<div class="action-group">
<button class="btn btn-primary">Создать дисциплину</button>
<button class="btn btn-secondary">Добавить затраты</button>
<button class="btn btn-success">Получить отчет за период</button>
<button class="btn btn-info">Отправить отчет на email</button>
</div>
</main>
</div>
</body>
</html>