Скриншот архива с проектом

Структура проекта

Задание
Разработать информационную систему для школы искусств. Приложение должно быть разработано на C# и Windows Forms с применением ООП. Приложение должно быть построено по принципу многоуровневой архитектуры - логика - интерфейс - тесты. Вам необходимо будет написать тесты. например для проверки пароля и цены курса - диапозон цен установите от 5 до 50 тысяч.
Функционал программы
- учёт студентов
- учёт администраторов
- учёт курсов
- учёт записей на курсы
- Выгрузка списка студентов, курсов, администраторов в Эксель
- Печать студентов, курсов и администраторов
- регистрация и авторизация с разделением на роли
- Модульные тесты
Дополнительно вы можете добавить - выгрузку в Эксель и печать для записей на курсы, а также добавить функционал для посещаемости курсов. Например курс по музыке был посещен 10 раз, а затем стало 8, итог - - 2. То есть принцип счетчика. Например было 8 а стало 12 - значит прирост +4.
Фрагмент программного кода (код формы Студенты)
using ArtSchool.BL.Models;
using ClosedXML.Excel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Windows.Forms;
namespace ArtSchool.UI
{
public partial class StudentsForm : Form
{
private AppDbContext context;
private List<Student> students;
private PrintDocument printDocument = new PrintDocument();
private int currentRow = 0;
private BindingSource studentsBindingSource = new BindingSource();
public StudentsForm()
{
InitializeComponent();
context = new AppDbContext();
printDocument.PrintPage += PrintDocument_PrintPage;
}
private void Populate()
{
students = context.Students.ToList();
studentsBindingSource.DataSource = new BindingList<Student>(students);
StudentsDGV.DataSource = studentsBindingSource;
// Скрытие ненужного столбца
if (StudentsDGV.Columns.Contains("Enrollments"))
{
StudentsDGV.Columns["Enrollments"].Visible = false;
}
if (StudentsDGV.Columns.Contains("FullName"))
{
StudentsDGV.Columns["FullName"].Visible = false;
}
bindingNavigator1.BindingSource = studentsBindingSource; // Привязка к BindingNavigator
}
private void StudentsForm_Load(object sender, EventArgs e)
{
Populate();
studentsBindingSource.CurrentChanged += StudentsBindingSource_CurrentChanged;
}
private void StudentsBindingSource_CurrentChanged(object sender, EventArgs e)
{
if (studentsBindingSource.Current is Student student)
{
IdTb.Text = student.StudentId.ToString();
SurnameTb.Text = student.Surname;
NameTb.Text = student.Name;
DateofBirthTb.Text = student.DateBirth.ToString("yyyy-MM-dd");
PhoneTb.Text = student.PhoneNumber;
EmailTb.Text = student.Email;
}
}
private void AddBtn_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(IdTb.Text) ||
string.IsNullOrWhiteSpace(SurnameTb.Text) ||
string.IsNullOrWhiteSpace(NameTb.Text) ||
string.IsNullOrWhiteSpace(DateofBirthTb.Text) ||
string.IsNullOrWhiteSpace(PhoneTb.Text) ||
string.IsNullOrWhiteSpace(EmailTb.Text))
{
MessageBox.Show("Пожалуйста, заполните все поля", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
var studentId = int.Parse(IdTb.Text);
if (context.Students.Any(s => s.StudentId == studentId))
{
MessageBox.Show("ID уже существует. Введите уникальный ID.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var student = new Student
{
StudentId = studentId,
Surname = SurnameTb.Text,
Name = NameTb.Text,
DateBirth = DateTime.Parse(DateofBirthTb.Text),
PhoneNumber = PhoneTb.Text,
Email = EmailTb.Text
};
context.Students.Add(student);
context.SaveChanges();
MessageBox.Show("Студент добавлен");
Populate();
}
catch (FormatException)
{
MessageBox.Show("Неверный формат данных. Проверьте ID и дату.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при добавлении: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void EditBtn_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(IdTb.Text))
{
MessageBox.Show("Укажите ID студента для редактирования.");
return;
}
try
{
int studentId = int.Parse(IdTb.Text);
var student = context.Students.FirstOrDefault(s => s.StudentId == studentId);
if (student == null)
{
MessageBox.Show("Студент не найден.");
return;
}
student.Surname = SurnameTb.Text;
student.Name = NameTb.Text;
student.DateBirth = DateTime.Parse(DateofBirthTb.Text);
student.PhoneNumber = PhoneTb.Text;
student.Email = EmailTb.Text;
context.SaveChanges();
MessageBox.Show("Данные обновлены");
Populate();
}
catch (Exception ex)
{
MessageBox.Show("Ошибка: " + ex.Message);
}
}
private void DeleteBtn_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(IdTb.Text))
{
MessageBox.Show("Укажите ID для удаления.");
return;
}
try
{
int studentId = int.Parse(IdTb.Text);
var student = context.Students.FirstOrDefault(s => s.StudentId == studentId);
if (student != null)
{
context.Students.Remove(student);
context.SaveChanges();
MessageBox.Show("Студент удален");
Populate();
}
else
{
MessageBox.Show("Студент не найден.");
}
}
catch (Exception ex)
{
MessageBox.Show("Ошибка: " + ex.Message);
}
}
private void ClosedBtn_Click(object sender, EventArgs e)
{
Close();
}
private void ExportBtn_Click(object sender, EventArgs e)
{
using (SaveFileDialog sfd = new SaveFileDialog()
{
Filter = "Excel Workbook|*.xlsx",
Title = "Сохранить как Excel файл"
})
{
if (sfd.ShowDialog() == DialogResult.OK)
{
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add("Студенты");
// Заголовки
for (int i = 0; i < StudentsDGV.Columns.Count; i++)
{
worksheet.Cell(1, i + 1).Value = StudentsDGV.Columns[i].HeaderText;
}
// Данные
for (int i = 0; i < StudentsDGV.Rows.Count; i++)
{
for (int j = 0; j < StudentsDGV.Columns.Count; j++)
{
worksheet.Cell(i + 2, j + 1).Value = StudentsDGV.Rows[i].Cells[j].Value?.ToString();
}
}
workbook.SaveAs(sfd.FileName);
MessageBox.Show("Экспорт завершён!", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
Font font = new Font("Arial", 10);
int rowHeight = 30;
int x = 50;
int y = 50;
// Заголовки
for (int i = 0; i < StudentsDGV.Columns.Count; i++)
{
e.Graphics.DrawString(StudentsDGV.Columns[i].HeaderText, font, Brushes.Black, x, y);
x += 150;
}
y += rowHeight;
x = 50;
// Строки
while (currentRow < StudentsDGV.Rows.Count)
{
DataGridViewRow row = StudentsDGV.Rows[currentRow];
x = 50;
for (int i = 0; i < StudentsDGV.Columns.Count; i++)
{
string value = row.Cells[i].Value?.ToString() ?? "";
e.Graphics.DrawString(value, font, Brushes.Black, x, y);
x += 150;
}
y += rowHeight;
currentRow++;
if (y > e.MarginBounds.Bottom)
{
e.HasMorePages = true;
return;
}
}
// Последняя страница
e.HasMorePages = false;
currentRow = 0;
}
private void PrintBtn_Click(object sender, EventArgs e)
{
using (PrintDialog printDialog = new PrintDialog())
{
printDialog.Document = printDocument;
if (printDialog.ShowDialog() == DialogResult.OK)
{
printDocument.Print();
}
}
}
private void StudentsDGV_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (StudentsDGV.SelectedRows.Count > 0)
{
var row = StudentsDGV.SelectedRows[0];
IdTb.Text = row.Cells["StudentId"].Value?.ToString();
SurnameTb.Text = row.Cells["Surname"].Value?.ToString();
NameTb.Text = row.Cells["Name"].Value?.ToString();
DateofBirthTb.Text = row.Cells["DateBirth"].Value?.ToString();
PhoneTb.Text = row.Cells["PhoneNumber"].Value?.ToString();
EmailTb.Text = row.Cells["Email"].Value?.ToString();
}
}
private void RecordsViewsBtn_Click(object sender, EventArgs e)
{
EnrollmentForm enrollmentForm = new EnrollmentForm();
enrollmentForm.ShowDialog();
}
}
}
Фрагмент программного кода (код модульного теста )
using ArtSchool.BL.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ArtSchool.UnitTests
{
[TestClass]
public class SecurityHelperTests
{
[TestMethod]
public void TestHashPassword()
{
// Arrange
string password = "123456";
string expectedHash = SecurityHelper.HashPassword(password); // Замените на реальный хэш
// Act
string actualHash = SecurityHelper.HashPassword(password);
// Assert
Assert.AreEqual(expectedHash, actualHash);
}
[TestMethod]
public void TestVerifyPassword()
{
// Arrange
string password = "123456";
string hashedPassword = SecurityHelper.HashPassword(password);
// Act
bool isValid = SecurityHelper.VerifyPassword(password, hashedPassword);
// Assert
Assert.IsTrue(isValid);
}
[TestMethod]
public void TestVerifyPasswordWithInvalidPassword()
{
// Arrange
string password = "123456";
string invalidPassword = "wrongpassword";
string hashedPassword = SecurityHelper.HashPassword(password);
// Act
bool isValid = SecurityHelper.VerifyPassword(invalidPassword, hashedPassword);
// Assert
Assert.IsFalse(isValid);
}
}
}
Пояснения по запуску программы
Для эффективной работы с приложением смотри приложенную инструкцию. Следуйте описанию в инструкции и у вас все получится. Приятного пользования.

Телеграм
-