Вложения типа деятельности

Это пятое пошаговое руководство из серии пошаговых руководств по дополнениям Classroom.

В этом пошаговом руководстве вы модифицируете пример из предыдущего шага, чтобы создать вложение типа задания. Это любые вложения, требующие отправки учащимся, например, письменный ответ, тест или другой созданный учащимся артефакт.

Важно различать вложения типа «контент» и вложения типа «активность». Вложения типа «активность» отличаются от вложений типа «контент» следующим:

  • Кнопка «Сдать» отображается в правом верхнем углу окна просмотра студента.
  • Они предоставляют уникальный идентификатор студенческой работы.
  • Карточка их вложений отображается в пользовательском интерфейсе оценщика Classroom.
  • Они могут выставить оценку за задание, к которому они относятся.

Обсуждение оценки см. в следующем пошаговом руководстве. В ходе этого пошагового руководства вы выполните следующие действия:

  • Измените предыдущие запросы на создание вложений в Classroom API, чтобы создать вложение типа «занятие».
  • Реализуйте постоянное хранилище для студенческих работ.
  • Измените предыдущий маршрут просмотра учащихся, чтобы принять вклад учащихся.
  • Укажите маршрут для обслуживания iframe для обзора студенческих работ.

После завершения работы вы можете создавать вложения к заданиям через интерфейс Google Classroom, войдя в систему как преподаватель. Учащиеся класса также могут выполнить задание в iframe и отправить ответ. Преподаватель может просмотреть работу учащегося в интерфейсе оценивания Classroom.

Для этого примера используйте шаблон вложения из предыдущего пошагового руководства, содержащий изображение известной достопримечательности и подпись с её названием. Задание заключается в том, чтобы предложить учащемуся назвать достопримечательность.

Изменить запрос на создание вложения

Перейдите к разделу кода, в котором вы создали вложение типа «контент» в предыдущем пошаговом руководстве. Ключевым элементом здесь является экземпляр объекта AddOnAttachment , в котором мы ранее указали teacherViewUri , studentViewUri и title для вложения.

Хотя все вложения дополнений требуют эти три поля, наличие или отсутствие studentWorkReviewUri определяет, относится ли вложение к типу «активность» или «контент». Запрос CREATE с заполненным studentWorkReviewUri становится вложением типа «активность», тогда как запрос CREATE без studentWorkReviewUri становится вложением типа «контент».

Единственное изменение, которое нужно внести в этот запрос, — заполнить поле studentWorkReviewUri . Добавьте сюда маршрут с соответствующим именем; он будет реализован на следующем этапе.

Питон

В нашем примере это метод create_attachments в файле webapp/attachment_routes.py .

attachment = {
    # Specifies the route for a teacher user.
    "teacherViewUri": {
        "uri":
            flask.url_for(
                "load_activity_attachment",
                _scheme='https',
                _external=True),
    },
    # Specifies the route for a student user.
    "studentViewUri": {
        "uri":
            flask.url_for(
                "load_activity_attachment",
                _scheme='https',
                _external=True)
    },
    # Specifies the route for a teacher user when the attachment is
    # loaded in the Classroom grading view.
    # The presence of this field marks this as an activity-type attachment.
    "studentWorkReviewUri": {
        "uri":
            flask.url_for(
                "view_submission", _scheme='https', _external=True)
    },
    # The title of the attachment.
    "title": f"Attachment {attachment_count}",
}

Добавить постоянное хранилище для вложений контента

Запишите ответ ученика на наше задание. Вы сможете посмотреть его позже, когда учитель проверит работу, в iframe «Обзор работ учеников».

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

  • attachment_id : уникальный идентификатор вложения. Присваивается Classroom и возвращается в ответе при создании вложения.
  • submission_id : идентификатор студенческой работы. Назначается Classroom и возвращается в ответе getAddOnContext в представлении «Студент».
  • student_response : Ответ, предоставленный студентом.

Питон

Расширьте реализацию SQLite и flask_sqlalchemy из предыдущих шагов.

Перейдите к файлу, в котором вы определили предыдущие таблицы ( models.py , если вы следуете нашему примеру). Добавьте следующий код в конец файла.

# Database model to represent a student submission.
class Submission(db.Model):
    # The attachmentId is the unique identifier for the attachment.
    submission_id = db.Column(db.String(120), primary_key=True)

    # The unique identifier for the student's submission.
    attachment_id = db.Column(db.String(120), primary_key=True)

    # The student's response to the question prompt.
    student_response = db.Column(db.String(120))

Импортируйте новый класс Submission в файл сервера с вашими маршрутами обработки вложений.

Изменить маршрут просмотра для студентов

Затем измените предыдущий маршрут «Представление студента», чтобы отобразить небольшую форму и принимать данные от студента. Вы можете повторно использовать большую часть кода из предыдущего пошагового руководства.

Найдите код сервера, предоставляющий маршрут для вашего студенческого представления. Этот маршрут указывается в поле studentViewUri при создании вложения. Первое изменение, которое нужно внести, — извлечь submissionId из ответа getAddOnContext .

Питон

В нашем примере это метод load_activity_attachment в файле webapp/attachment_routes.py .

# Issue a request to the courseWork.getAddOnContext endpoint
addon_context_response = classroom_service.courses().courseWork(
).getAddOnContext(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"]).execute()

# One of studentContext or teacherContext will be populated.
user_context = "student" if addon_context_response.get(
    "studentContext") else "teacher"

# If the user is a student...
if user_context == "student":
    # Extract the submissionId from the studentContext object.
    # This value is provided by Google Classroom.
    flask.session["submissionId"] = addon_context_response.get(
            "studentContext").get("submissionId")

Вы также можете отправить запрос на получение статуса работы учащегося . Ответ содержит значение SubmissionState , которое указывает, открыл ли учащийся вложение или сдал его. Это может быть полезно, если вы хотите запретить редактирование сданной работы или хотите предоставить учителю информацию об успеваемости его учеников:

Питон

В приведенном нами примере это продолжение метода load_activity_attachment , описанного выше.

# Issue a request to get the status of the student submission.
submission_response = classroom_service.courses().courseWork(
).addOnAttachments().studentSubmissions().get(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"],
    attachmentId=flask.session["attachmentId"],
    submissionId=flask.session["submissionId"]).execute()

Наконец, извлеките информацию о вложении из нашей базы данных и предоставьте форму ввода. Форма в нашем примере состоит из поля ввода и кнопки «Отправить». Покажите изображение достопримечательности и предложите учащемуся ввести её название. После того, как он даст ответ, сохраните его в нашей базе данных.

Питон

В приведенном нами примере это продолжение метода load_activity_attachment , описанного выше.

# Look up the attachment in the database.
attachment = Attachment.query.get(flask.session["attachmentId"])

message_str = f"I see that you're a {user_context}! "
message_str += (
    f"I've loaded the attachment with ID {attachment.attachment_id}. "
    if user_context == "teacher" else
    "Please complete the activity below.")

form = activity_form_builder()

if form.validate_on_submit():
    # Record the student's response in our database.

    # Check if the student has already submitted a response.
    # If so, update the response stored in the database.
    student_submission = Submission.query.get(flask.session["submissionId"])

    if student_submission is not None:
        student_submission.student_response = form.student_response.data
    else:
        # Store the student's response by the submission ID.
        new_submission = Submission(
            submission_id=flask.session["submissionId"],
            attachment_id=flask.session["attachmentId"],
            student_response=form.student_response.data)
        db.session.add(new_submission)

    db.session.commit()

    return flask.render_template(
        "acknowledge-submission.html",
        message="Your response has been recorded. You can close the " \
            "iframe now.",
        instructions="Please Turn In your assignment if you have " \
            "completed all tasks."
    )

# Show the activity.
return flask.render_template(
    "show-activity-attachment.html",
    message=message_str,
    image_filename=attachment.image_filename,
    image_caption=attachment.image_caption,
    user_context=user_context,
    form=form,
    responses=response_strings)

Чтобы различать пользователей, рассмотрите возможность отключения функции отправки и вместо этого отображения правильного ответа в окне учителя.

Добавить маршрут для iframe «Обзор студенческих работ»

Наконец, добавьте маршрут для обслуживания iframe «Обзор студенческой работы». Имя этого маршрута должно совпадать с именем, указанным для studentWorkReviewUri при создании вложения. Этот маршрут открывается, когда преподаватель просматривает работу студента в интерфейсе оценщика Classroom.

Параметр запроса submissionId вы получаете, когда Classroom открывает iframe для проверки работ учащегося. Используйте его для извлечения работы учащегося из локальной базы данных:

Питон

В нашем примере это файл webapp/attachment_routes.py .

@app.route("/view-submission")
def view_submission():
    """
    Render a student submission using the show-student-submission.html template.
    """

    # Save the query parameters passed to the iframe in the session, just as we did
    # in previous routes. Abbreviated here for readability.
    add_iframe_query_parameters_to_session(flask.request.args)

    # For the sake of brevity in this example, we'll skip the conditional logic
    # to see if we need to authorize the user as we have done in previous steps.
    # We can assume that the user that reaches this route is a teacher that has
    # already authorized and created an attachment using the add-on.

    # In production, we recommend fully validating the user's authorization at
    # this stage as well.

    # Look up the student's submission in our database.
    student_submission = Submission.query.get(flask.session["submissionId"])

    # Look up the attachment in the database.
    attachment = Attachment.query.get(student_submission.attachment_id)

    # Render the student's response alongside the correct answer.
    return flask.render_template(
        "show-student-submission.html",
        message=f"Loaded submission {student_submission.submission_id} for "\
            f"attachment {attachment.attachment_id}.",
        student_response=student_submission.student_response,
        correct_answer=attachment.image_caption)

Протестируйте дополнение

Повторите шаги по тестированию дополнения из предыдущего руководства . У вас должно получиться вложение, которое ученик сможет открыть.

Для проверки прикрепленного файла активности выполните следующие действия:

  • Войдите в Google Classroom как один из тестовых пользователей- учеников в том же классе, что и тестовый пользователь-учитель.
  • Перейдите на вкладку «Работа в классе» и разверните тестовое задание .
  • Щелкните карточку вложения , чтобы открыть представление «Студент» и отправить ответ на задание.
  • Закройте iframe после завершения задания. При желании нажмите кнопку «Сдать» .

После завершения задания в Classroom не должно произойти никаких изменений. Теперь проверьте iframe «Обзор студенческих работ»:

  • Войдите в систему Classroom как тестовый пользователь- учитель .
  • Найдите столбец с вашим тестовым заданием на вкладке «Оценки» . Нажмите на название вашего тестового задания.
  • Найдите карточку тестируемого учащегося. Нажмите на вложение на карточке.

Подтвердите, что для студента отображается правильная заявка.

Поздравляем! Вы готовы перейти к следующему шагу: синхронизации оценок вложений .