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

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

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

コンテンツ タイプとアクティビティ タイプの添付ファイルの違いは重要です。アクティビティ タイプの添付ファイルは、次の点でコンテンツ タイプと異なります。

  • Student View iframe の右上に [提出] ボタンが表示されます。
  • 生徒の提出物を一意に識別できる。
  • Classroom の採点ツールの UI に添付ファイルのカードが表示されます。
  • 生徒は、自分が所属する課題に成績を設定できます。

採点については、次のチュートリアルをご覧ください。このチュートリアルの手順では、次のことを完了します。

  • Classroom API に対する以前の添付ファイル作成リクエストを変更して、アクティビティ形式の添付ファイルを作成します。
  • 生徒の提出物用に永続ストレージを実装します。
  • 以前の [Student View] で、生徒の入力を受け入れるようルートを変更します。
  • 「生徒の提出物の確認」 iframe を配信するためのルートを指定します。

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

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

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

前のチュートリアルで Content-Type アタッチメントを作成したコードのセクションに移動します。ここでの重要なアイテムは、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: 生徒の提出物の識別子。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()

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

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)

アドオンをテストする

前のチュートリアルのアドオンの手順をテストするを繰り返します。生徒が開くことのできる添付ファイルが必要です。

アクティビティのアタッチメントをテストするには、次の手順を行います。

  • 教師によるテストユーザーと同じクラスの生徒のテストユーザーの 1 人として Google Classroom にログインします。
  • [授業] タブに移動し、テストの [課題] を開きます。
  • アドオン添付ファイル カードをクリックして生徒ビューを開き、アクティビティの回答を送信します。
  • アクティビティが完了したら iframe を閉じます。必要に応じて、[提出] ボタンをクリックします。

このアクティビティを完了した後、Classroom に変化は見られません。次に、「生徒の提出物の確認」iframe をテストします。

  • 教師のテストユーザーとして Classroom にログインします。
  • [採点] タブでテスト課題の列を探します。テスト割り当ての名前をクリックします。
  • テスト用受講者ユーザーのカードを見つけます。カード上の添付ファイルをクリックします。

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

これで完了です。次のステップ(添付ファイルの成績の同期)に進む準備が整いました。