これは、Classroom アドオンのチュートリアル シリーズの 5 番目のチュートリアルです。
このチュートリアルでは、前のチュートリアルの手順の例を変更して、アクティビティ タイプのアタッチメントを生成します。生徒の提出物(記述式の解答、テスト、生徒が作成したその他の成果物など)が必要な添付ファイル。
コンテンツ タイプとアクティビティ タイプの添付ファイルの違いは重要です。アクティビティ タイプの添付ファイルは、コンテンツ タイプとは次の点で異なります。
- [提出] ボタンが、生徒用ビューの iframe の右上に表示されます。
- 生徒の課題に一意の識別子を提供します。
- 添付ファイル カードが Classroom の採点ツール UI に表示されます。
- 所属する課題の成績を設定できます。
採点については、次のチュートリアルをご覧ください。このチュートリアルでは、次のことを行います。
- 以前の Classroom API への添付ファイル作成リクエストを変更して、アクティビティ タイプの添付ファイルを作成します。
- 生徒の提出物の永続ストレージを実装します。
- 前の生徒ビューのルートを変更して、生徒の入力を受け入れるようにします。
- 生徒の課題のレビューの iframe を提供するルートを指定します。
完了すると、教師としてログインしているときに、Google Classroom の UI を通じて課題にアクティビティ タイプ添付ファイルを作成できます。クラスの生徒は、iframe でアクティビティを完了して回答を送信することもできます。教師は Classroom の採点 UI で生徒の提出物を確認できます。
この例では、前のチュートリアルで使用した添付ファイル テンプレートを再利用します。このテンプレートには、有名なランドマークの画像と、ランドマークの名前を含むキャプションが表示されます。このアクティビティでは、生徒にランドマークの名前を入力するよう求めます。
添付ファイル作成リクエストを変更する
前のチュートリアルでコンテンツ タイプ添付ファイルを作成したコードのセクションに移動します。ここで重要な項目は AddOnAttachment オブジェクトのインスタンスです。このインスタンスでは、以前にアタッチメントの teacherViewUri、studentViewUri、title を指定しました。
すべてのアドオン アタッチメントにはこれらの 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()
最後に、データベースから添付ファイル情報を取得し、入力フォームを提供します。提供されている例のフォームは、文字列入力フィールドと送信ボタンで構成されています。ランドマークの画像を表示し、生徒にその名前を入力するよう求めます。回答が得られたら、データベースに記録します。
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 を閉じます。必要に応じて、[提出] ボタンをクリックします。
アクティビティを完了しても、Classroom に変更は表示されません。生徒の提出物の確認 iframe をテストします。
- 教師のテストユーザーとして Classroom にログインします。
- [成績] タブで、テスト課題の列を見つけます。テスト課題の名前をクリックします。
- テスト生徒ユーザーのカードを見つけます。カードの添付ファイルをクリックします。
生徒に正しい課題が提出されていることを確認します。
おめでとうございます!次のステップ(添付ファイルの評価を同期する)に進む準備ができました。