アクティビティ タイプの添付ファイル

これは、Classroom アドオンのチュートリアル シリーズの5 つ目のチュートリアルです。

このチュートリアルでは、前のチュートリアルの手順の例を変更して、アクティビティ タイプのアタッチメントを生成します。生徒の提出が必要な添付ファイル(書面による回答、クイズ、生徒が作成したその他のアーティファクトなど)です。

コンテンツ タイプとアクティビティ タイプのアタッチメントを区別することが重要です。アクティビティ タイプのアタッチメントは、コンテンツ タイプのアタッチメントとは次の点で異なります。

  • 生徒ビューの iframe の右上に [提出] ボタンが表示されます。
  • 生徒の課題の一意の識別子を提供します。
  • 添付カードが Classroom 採点者の UI に表示されます。
  • 生徒は、自分が所属する課題の成績を設定できます。

採点については、次のチュートリアルをご覧ください。このチュートリアルでは、次の作業を行います。

  • アクティビティ タイプのアタッチメントを作成するように、Classroom API に対する以前のアタッチメント作成リクエストを変更します。
  • 生徒の提出物の永続ストレージを実装する。
  • 生徒の入力を受け付けるように、前の生徒ビュー ルートを変更します。
  • 生徒の課題の確認用 iframe を提供するルートを指定します。

作成が完了したら、教師としてログインして Google Classroom UI から、課題にアクティビティ タイプの添付ファイルを作成できます。クラスの生徒は、iframe 内でアクティビティを完了して回答を送信することもできます。教師は Classroom の採点 UI で生徒の提出物を確認できます。

この例では、有名なランドマークの画像と、ランドマークの名前を含むキャプションを表示する、前回のチュートリアルの添付テンプレートを再利用します。このアクティビティでは、ランドマークの名前を入力するよう生徒に促します。

アタッチメント作成リクエストを変更する

前のチュートリアルでコンテンツ タイプのアタッチメントを作成したコードのセクションに移動します。ここで重要なのは、AddOnAttachment オブジェクトのインスタンスです。このオブジェクトでは、アタッチメントの teacherViewUristudentViewUrititle を以前に指定しました。

すべてのアドオン アタッチメントにはこれらの 3 つのフィールドが必要ですが、studentWorkReviewUri の有無によって、アタッチメントがアクティビティ タイプかコンテンツ タイプかが決まります。studentWorkReviewUri が設定された CREATE リクエストはアクティビティ タイプの添付ファイルになり、studentWorkReviewUri のない CREATE リクエストはコンテンツ タイプの添付ファイルになります。

このリクエストに変更を加える必要があるのは、studentWorkReviewUri フィールドに値を入力することのみです。適切な名前のルートをここに追加します。このルートは後で実装します。

Python

提供されている例では、これは webapp/attachment_routes.py ファイルの create_attachments メソッド内にあります。

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: 生徒の提出物の ID。Classroom によって割り当てられ、生徒ビューの getAddOnContext レスポンスで返されます。
  • student_response: 生徒が提供した回答。

Python

前の手順の 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 フィールドで指定されたルートです。最初に行う変更は、getAddOnContext レスポンスから submissionId を抽出することです。

Python

提供されている例では、これは webapp/attachment_routes.py ファイルの load_activity_attachment メソッドにあります。

# 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 値が含まれます。これは、生徒が添付ファイルを開いたかどうか、提出したかどうかなどの状態を示します。これは、提出された提出物の編集を禁止する場合や、生徒の進捗状況に関する教師向けの分析情報を提供する場合に便利です。

Python

提供されている例では、これは上記の 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()

最後に、データベースから添付ファイル情報を取得し、入力フォームを表示します。サンプルのフォームは、文字列入力フィールドと送信ボタンで構成されています。ランドマークの画像を表示し、その名前を入力するよう生徒に伝えます。回答が得られたら、データベースに記録します。

Python

提供されている例では、これは上記の 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 採点ツールの UI で生徒の提出物を確認すると開きます。

Classroom が生徒の提出物レビューの iframe を開いたときに、submissionId クエリ パラメータが返されます。これを使用して、ローカル データベースから生徒の課題を取得します。

Python

提供されている例では、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 を閉じます。必要に応じて、[Turn In] ボタンをクリックします。

アクティビティの完了後に Classroom に変更は表示されません。次に、生徒の提出物の確認の iframe をテストします。

  • 教師のテストユーザーとして Classroom にログインします。
  • [成績] タブで、テスト課題の列を見つけます。テスト課題の名前をクリックします。
  • テスト用の生徒ユーザーのカードを見つけます。カードの添付ファイルをクリックします。

生徒の正しい提出物が表示されていることを確認します。

これで、これで、次のステップである添付ファイルの成績の同期に進むことができます。