# Разбор модуля 4 предварительного задания демо-экзамена 2026 года ## Доработка структуры БД >Для выполнения задания рекомендуется создать в базе данных таблицу "Пользователи". Если такая таблица уже существует, необходимо внести некоторые изменения для реализации дальнейшего функционала приложения. Просто добавте таблицу с полями `login`, `password`, `role`, `enabled` и добавьте в нее пару записей с разными ролями (в этом модуле уже не оценивается ERD, поэтому делать таблицу ролей не обязательно) ## Авторизация по логиину/паролю >Разработайте форму для авторизации зарегистрированных пользователей с ролями "Администратор" и "Пользователь". Форма должна содержать поля текстовые поля логин, пароль и кнопку "Войти". Поля "Логин" и "Пароль" должны быть обязательными для заполнения. При неверно введенных данных, пользователь должен получить сообщение об ошибке "Вы ввели неверный логин или пароль. Пожалуйста проверьте ещё раз введенные данные". > >После успешной авторизации пользователь должен получить сообщение "Вы успешно авторизовались". > >При аутентификации связка «логин/пароль» должна совпадать с одной из записей в таблице "Пользователи". Тут все просто: заполняем логин/пароль и ищем в БД НЕ ЗАБЛОКИРОВАННОГО (`enabled = 1`) пользователя с таким логином и паролем ## Интерактивная капча >На страницу авторизации добавьте интерактивную капчу, в которой пользователю необходимо собрать исходное изображение из фрагментов. Метод сборки изображения может быть произвольным. После сборки изображения система проверяет правильность расположения фрагментов. > >Если пазл собран верно — пользователь проходит проверку и может авторизоваться. Мы в рамках лекций с картинками особенно не работали - закроем этот пробел. Что нам необходимо сделать: - вывести в окне 4 картинки в случайные кооринаты - реализовать перемещение картинок по окну - проверить правильно ли собран паззл ### Вывод картинок 1. Создайте в окне именованный элемент __Canvas__ (у меня тестовое приложение, в котором он занимает все содержимое окна, вы вписывайте в форму авторизации) ```xml ``` 1. Создайте в проекте каталог __images__ и скопируйте в него части паззла ![](../img/de26_m4_01.png) Не забудьте каждое изображение включить в ресурсы ![](../img/de26_m4_02.png) 1. По идее картинки можно закинуть в канвас и руками, но я приведу программный способ: В конструкторе окна добавьте следующий код ```cs // это стандартное содержимое конструктора InitializeComponent(); // дальше добавляемый код // создаем экземпляр генератора случайных чисел var random = new Random(); for (int i = 1; i < 5; i++) { // создаем новую картинку Image myImage = new Image(); // в качестве источника устанавливаем один из кусочков паззла myImage.Source = new BitmapImage( new Uri($"/images/{i}.png", UriKind.Relative) ); // оригинальное изображение 700px, // это, на мой взгляд, многовато - задаем // альтернативный размер изображения myImage.Width = 200; // присваиваем обработчику клика левой кнопкой // делегат (функцию обработчки) myImage.MouseLeftButtonDown += Image_MouseLeftButtonDown; // задаем левую/верхнюю точку для изображения // случайным образом // в параметрах метода Next минимальное и максимальное // значение результата Canvas.SetLeft(myImage, random.Next(0, 200)); Canvas.SetTop(myImage, random.Next(0, 200)); // добавляем созданное и настроенное // изображение на холст (Canvas) // (DragArena - название холста) DragArena.Children.Add(myImage); } ``` И в класс окна дописываем поля, обработчики клика и движения мыши ```cs private Image? draggingImage; private void Image_MouseLeftButtonDown( object sender, MouseButtonEventArgs e) { // на всякий случай проверяем, что кликнули по Image if (e.Source is Image image) { // запоминаем элемент, который будем двигать draggingImage = image; // вычисляем и запоминаем текущую координату relativeMousePos = e.GetPosition(draggingImage) - new Point(); // задаем делегаты для отслеживания движения draggingImage.MouseMove += OnDragMove; draggingImage.LostMouseCapture += OnLostCapture; draggingImage.MouseUp += OnMouseUp; Mouse.Capture(draggingImage); } } // при движении мыши обновляем позицию активной картинки void OnDragMove(object sender, MouseEventArgs e) { UpdatePosition(e); } void UpdatePosition(MouseEventArgs e) { var point = e.GetPosition(DragArena); var newPos = point - relativeMousePos; Canvas.SetLeft(draggingImage, newPos.X); Canvas.SetTop(draggingImage, newPos.Y); } void OnMouseUp(object sender, MouseButtonEventArgs e) { FinishDrag(sender, e); Mouse.Capture(null); } void OnLostCapture(object sender, MouseEventArgs e) { FinishDrag(sender, e); } // при отпускании мыши отписываемся от делегатов void FinishDrag(object sender, MouseEventArgs e) { draggingImage.MouseMove -= OnDragMove; draggingImage.LostMouseCapture -= OnLostCapture; draggingImage.MouseUp -= OnMouseUp; UpdatePosition(e); } ``` Если все сделали правильно, то при зпуске приложения увидим что-то подобное: ![](../img/de26_m4_03.png) Картинки перетаскиваютс мышкой и складываются в картинку ![](../img/de26_m4_04.png) Код для проверки "собранности" паззла я не привожу, он примитивный - нужно сравнить координаты соседних кусочков паззла (для этого создать массив и записать созданные изображения в него), заложив допустимую дельту, чтобы не целиться с точностью до пикселя ## Блокировка аккаунта >Если в течении 3-х раз подряд пазл собран не верно или не верно введен пароль, то учетная запись блокируется и при повторной авторизации должно появляться сообщение "Вы заблокированы. Обратитесь к администратору". Меняем в БД поле `enabled` на `0` ## CRUD пользователей >На рабочем столе пользователя с ролью "Администратор" предусмотрите функционал для добавления новых пользователей, изменения данных текущих пользователей (включая снятие блокировки). При добавлении нового пользователя следует проверять его наличие в базе данных. В случае, если пользователь с указанным логином уже существует, должно выводиться соответствующее сообщение. Тут обычный список пользователей с возможностью содания, удаления и редактироания