Найти в Дзене
Logonok

Создание приложения для дистанционного обучения

Оглавление

Дистанционное обучение реализуется как клиент-серверное приложение с интерфейсом в браузере. Пользователи авторизуются для доступа к системе с поддержкой разделение прав - учитель или ученик. Учителя создают учебные материалы (уроки и вопросы), назначают задания, проверяют и оценивают работы учеников. Ученики могут просматривать материалы уроков и выполнять задания. Каждое задание можно обсудить в комментариях.

Создавать систему обучения будем на декларативном фреймворке Evado, который обеспечивает готовый функционал для веб-приложения, тем самым избавляя от необходимости писать код. Пример создания подобного приложения можно найти в этой статье.

Устанавливаем и запускаем шаблон приложение как описано в инструкции. После чего переходим в модуль Студия для создания метаданных.

Метаданные

Сущности приложения можно разделить на три взаимосвязанные части: участники системы, учебные материалы и задания. Участники - это учителя и ученики. Учебные материалы - это уроки и вопросы по ним, проверяющие полученные знания. Задания - это ответы, которые предлагают ученики на вопросы, и обсуждение этих ответов.

Классы и атрибуты описывают сущности приложения
Классы и атрибуты описывают сущности приложения

Первым делом создаем классы, которые описывают участников. Создаем класс Учитель (teacher). Добавляем атрибут Пользователь (user) с типом Системный пользователь. Данный атрибут будет хранить связь учителя с пользователем, который авторизуется в приложении. Создаем класс Ученик (student) и также добавляем атрибут Пользователь (user).

Далее создаем класс Урок (lesson), который содержит информацию урока и его название. Для этого добавляем строковый атрибут Название (name) и текстовый атрибут Содержание (content).

Каждый урок должен содержать вопросы для проверки обучения. Для этого создаем класс Вопрос (question). Добавляем текстовый атрибут Текст (text), который будет хранить содержимое вопроса. Для связи вопроса с уроком создаем ссылочный атрибут Урок (lesson).

Создаем класс Задание (task), который описывает ответ ученика на вопрос, обсуждение и оценку этого ответа. Добавляем ссылочный атрибут Ученик (student), который будет связывать задание к конкретным учеником. Добавляем ссылочный атрибут Вопрос (question) для связи задания с вопросом. Добавляем текстовый атрибут Текст (text) для содержимого ответа.

И, наконец, добавляем целочисленный атрибут Оценка (grade) для оценки ответа учителем. Переходим на вкладку Перечисления и создаем текстовые метки для оценок.

Перечисление создает ярлыки для хранимых значений  атрибута
Перечисление создает ярлыки для хранимых значений атрибута

При выполнении задания, до или после его оценки неизбежно будут возникать вопросы, как ученика, так и учителя. Для их обсуждения сделаем возможность комментировать задание.

Создаем класс Комментарий (comment). Добавляем ссылочный атрибут Задание (task) для связи с заданием и текстовый атрибут Текст (text) для содержимого комментария. Кроме того, необходимо отобразить некоторые служебные данные. Для этого добавляем атрибуты Создатель (_creator), который отобразит пользователя, создавшего объект, и Дата создания (_createdAt) с типом Дата и представлением Локальная дата и время. Атрибуты, описывающие служебные данные, должны быть только для чтения.

Локальное представление даты учитывает часовой пояс клиента. Таким образом представление одной и той же даты будет различным для клиентов из разных часовых поясов.

Далее необходимо создать вычисляемые атрибуты связей. Атрибут с типом Обратная ссылка не хранит значение связи, а извлекает его из указанного отношения.

В атрибуте с типом Обратная ссылка отношение для вычисления связи
В атрибуте с типом Обратная ссылка отношение для вычисления связи

Возвращаемся в класс Задание и создаем атрибут Комментарии (comments) как обратную ссылку на класс Комментарий. Эта множественная связь позволяет найти все комментарии, которые ссылаются на задание. Переходим в класс Вопрос и создаем обратную ссылку Задания (tasks) для получения всех заданий, связанных с вопросом. Переходим в класс Урок и создаем обратную ссылку Вопросы (questions) для получения всех вопросов, ссылающихся на урок.

Бизнес-процессы

Каждый объект класса может быть в определенном состоянии. Это позволяет определять специальный функционал для некоторых объектов.

Переходим в класса Задание и создаем служебный строковый атрибут Состояние (_state), который отражает значение состояния конкретного задания. Далее выбираем вкладку Состояния, в которой представлен список всевозможных состояний объектов.

Создаем состояние Черновик (draft), означающее, что ученик работает над заданием. Это состояние будет по умолчанию назначаться на все новые объекты. Создаем состояние Ожидание (pending), означающее окончание работы и ожидание проверки. Далее создаем состояние Проверка (checking), означающее, что учитель начал проверять решение. И, наконец, финальное состояние Закрыто (closed), когда выставлена оценка. В этом состоянии объект доступен только для чтения.

Возможные состояния объектов класса Задание
Возможные состояния объектов класса Задание

Для изменения состояний используются переходы. Переход определяет как может измениться состояние. У перехода может быть несколько начальных состояний, в том числе и пустое, но только одно конечное состояние.

  • Создаем переход Готово (ready) из начального состояния Черновик в конечное состояние Ожидание.
  • Создаем переход Проверить (check) из состояния Ожидание в состояние Проверка.
  • Создаем переход Завершить (complete) из состояния Проверка в состояние Закрыто.
  • Создаем переход Переделать (rework) из состояния Проверка в состояние Черновик.
  • Создаем переход Перепроверить (recheck) из состояния Закрыто в состояние Проверка.

Экспортируем созданные метаданные с помощью кнопки на верхней панели.

Безопасность доступа

Важным компонентом клиент-серверного приложения является разграничение прав пользователей. Для управления правами перейдем в модуль Администрирования.

Роли определяют права пользователя
Роли определяют права пользователя

Во фреймворке Evado реализовано управление доступом на основе ролей, разрешений и правил. Например, нам нужно позволить пользователю редактировать только собственные статьи. Для этого создается разрешение, позволяющее пользователю редактировать статьи. Затем создается правило, проверяющее является ли пользователем автором статьи. Далее создается роль Писатель, и к ней добавляется созданное разрешение. Теперь любой пользователь, получивший роль Писатель, сможет редактировать собственные статьи. Для удобства управления разрешения могут объединяться в иерархию - дети-родители.

Разрешение для метаданных может быть либо запрещающим, либо разрешающим. Также явно указываются допустимые действия - чтение, создание, редактирование и/или удаление. Кроме того, отсутствует структурная иерархия, а наследование доступа определяется типом сущности. Например, если разрешен доступ к классу, то автоматически разрешается доступ ко всем его представлениям.

Права на комментарии

Нам нужно разрешить ученику читать комментарии только тех заданий, которые ему назначены.

Разрешение читать комментарий только из назначенных заданий
Разрешение читать комментарий только из назначенных заданий

Для этого создадим разрешения метаданных с типом Разрешить и действием Читать. Добавим цель класс Комментарий и роль - Ученик. Для ограничения комментариев только принадлежащим ученику заданиями создадим правило TaskCommentReaderRule. Правила разрешений описываются отдельными классами и могут реализовывать любой требуемый функционал.

Метод execute вызывается в момент проверки разрешения. В нем определяется, что является целью проверки - объект задания или список объектов.

В методе checkReader сначала находим идентификатор ученика (student), который соответствует проверяемому заданию, а затем находим идентификатор пользователя (user), который соответствует этому ученику. Если идентификатор совпадает с текущим пользователем системы, то правило выполняется успешно.

Здесь следует обратить внимание на то, что разрешение срабатывает, если результат выполнения правила равен true. Если изменить тип разрешения на Запретить, то получится, что только ученик привязанный к данному заданию не сможет читать комментарии. А чтобы запретить чтение всем ученикам, кроме привязанного, придется сделать новое правило. Универсальный вариант - это проверить тип разрешения и обратить результат при запрещающем типе. Теперь, если разрешение станет запрещающим, правило будет возвращать true для всех учеников, кроме привязанного к заданию.

Для того, чтобы изменения системы безопасности вступили в силу необходимо перезапустить ее кнопкой на верхней панели.

Дополнительная функциональность

Переходим в модуль Офис и создаем учителей, учеников, уроки, вопросы. Обратите внимание, что из вопроса можно создать только одно задание, привязывая его к конкретному ученику. Но намного удобнее создавать задания для всех учеников разом. Для этого необходимо реализовать утилиту.

Утилита получает от пользователя текущий вопрос (data.model). Затем для каждого ученика создается задание, привязанное к данному вопросу. Чтобы кнопка утилиты отображалась в форме, нужно добавить конфигурацию в config/default-utilities:

questionTaskCreation: {
Class: 'component/meta/utility/QuestionTaskCreationUtility',
name: 'Создать задания',
hint: 'Создать задания для всех учеников',
enabled: true,
frontClass: 'QuestionTaskCreation',
targetClass: 'question',
actions: ['update']
}

Свойство Class определяет класс утилиты. Свойство targetClass определяет код класса, к которому привязана утилита. Свойство actions определяет действия с объектов, в которых утилита будет отображаться:

  • create - создание объекта,
  • update - редактирование объекта)

В свойстве frontClass определено имя класса для управления утилитой на стороне клиента (в браузере).

Кнопка запуска утилиты, создающей задания по данному вопросу для всех учеников
Кнопка запуска утилиты, создающей задания по данному вопросу для всех учеников

Итог

Готовое приложение для запуска, изучения и модификаций доступно на гитхабе.