外部添付ファイルと提出

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

このチュートリアルでは、ウェブアプリに動作を追加して、Google Classroom の外部からアドオンの添付ファイルを作成します。この動作を使用すると、ユーザーが既存の商品またはウェブサイトからアドオンの添付ファイルを作成できます。これは CourseWork 統合にも適しています。フローを変えることなく、既存のトラフィックをアドオンが提供する優れたユーザー エクスペリエンスに誘導できるためです。推奨されるプロセスについては、Classroom の外部で添付ファイルを作成するガイドページをご覧ください。

また、アドオンの添付ファイルを使用して課題をプログラムで変更する動作をアドオンに追加します。課題の作成者に関わらず、アドオン アタッチメントが添付されている課題はすべて変更できます。これは、生徒がアクティビティを完了した後に課題を提出する場合に特に便利です。割り当てられたタスクが完了し、生徒の課題を確認できる状態であることを教師に知らせることができます。

content-type またはactivity-type の添付ファイルをサポートする最終バージョンのアドオンを拡張します。このガイドでは、コンテンツ タイプのアタッチメントを使用します。

課題管理の OAuth スコープを追加する

アプリが次のスコープをリクエストしていることを確認します。

  • https://www.googleapis.com/auth/classroom.addons.teacher
  • https://www.googleapis.com/auth/classroom.addons.student
  • https://www.googleapis.com/auth/classroom.coursework.students

classroom.coursework.students スコープは以前は必要ありませんでしたが、CourseWork の割り当ての作成または変更に使用されます。このスコープを、Cloud プロジェクトの Google Workspace Marketplace SDKOAuth 同意画面、サーバーコードのスコープのリストに追加します。

Python

  SCOPES = [
    "https://www.googleapis.com/auth/classroom.addons.teacher",
    "https://www.googleapis.com/auth/classroom.addons.student",
    "https://www.googleapis.com/auth/classroom.coursework.students",
  ]

Classroom で課題を作成する

iframe を使用しないウェブページにボタンを追加する

このチュートリアルで説明するフローでは、ユーザーが Google 以外のプロダクトから Google Classroom の課題と添付ファイルを作成できます。実際には、既存のウェブサイトまたはアプリケーションである可能性があります。この例では、外部サイトとして機能するモック ウェブページを作成する必要があります。クリックすると、推奨される CourseWork フローを実行して新しい課題を作成する新しいルートを開くボタンまたはリンクが必要です。

また、ユーザーがログインできるようにボタンまたはリンクを追加する必要があります(まだ追加していない場合)。後続の API リクエストを行うにはユーザー認証情報が必要になるため、OAuth 2.0 ハンドシェイクを完了する必要があります。具体的なガイダンスについては、ログイン チュートリアルをご覧ください。

Python

提供されている Python の例では、最初のチュートリアルの手順で説明した /index ルートを変更します。

<!-- /webapp/templates/index.html -->
<a href="clear-credentials.html">Logout</a>
<a href="start-auth-flow.html">Login</a>

<br>

<a href="create-coursework-assignment.html">Create a CourseWork Assignment</a>

ウェブサイトにデスティネーションを表す HTML テンプレートを追加します。このページには、CourseWork アサインメントに添付されるコンテンツが表示されます。

<!-- /webapp/templates/example-coursework-assignment.html -->
<h1>CourseWork assignment loaded!</h1>
<p>You've loaded a CourseWork assignment! It was created from an external web page.</p>

CourseWork 関連のルートを処理する新しい Python モジュール ファイルを作成します。サンプルでは coursework_routes.py です。次の 3 つのルートを追加します。一部の内容は後で入力します。

# /webapp/coursework_routes.py
@app.route("/create-coursework-assignment")
def create_coursework_assignment():
  """
  Completes the assignment creation flow.
  """

  # Check that the user is signed in. If not, perform the OAuth 2.0
  # authorization flow.
  credentials = get_credentials()

  if not credentials:
    return start_auth_flow("coursework_assignment_callback")

  # Construct the Google Classroom service.
  classroom_service = get_classroom_service()

  pass  # To be completed later.

@app.route("/example-coursework-assignment/<assignment_type>")
def example_coursework_assignment(assignment_type):
  """
  Renders the "example-coursework-assignment.html" template.
  """
  return flask.render_template(
      "example-coursework-assignment.html", assignment_type=assignment_type
  )

@app.route("/coursework-assignment-callback")
def coursework_assignment_callback():
  """
  Completes the OAuth 2.0 handshake and stores credentials in the session.
  This is identical to the callback introduced in the sign-in walkthrough,
  but redirects the user to the index page instead of the attachment
  discovery page.
  """
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE,
      scopes=SCOPES,
      state=flask.session["state"],
      redirect_uri=flask.url_for("coursework_assignment_callback", _external=True),
  )

  flow.fetch_token(authorization_response=flask.request.url)

  credentials = flow.credentials
  flask.session["credentials"] = session_credentials_to_dict(
      credentials
  )

  # Close the current window and redirect the user to the index page.
  return flask.render_template("close-me.html", redirect_destination="index")

ユーザーが添付ファイルを作成できるかどうかを確認する

ユーザーに代わってアドオン アタッチメントを作成するには、ユーザーがいくつかの前提条件を満たしている必要があります。ユーザーがこれらの前提条件を満たしているかどうかを判断するために、userProfiles.checkUserCapability メソッドが用意されています。前提条件を満たすユーザーを対象ユーザーと呼びます。

CourseWork 作成ルートの実装に適格性チェックを追加。次に、レスポンスの allowed フィールドをテストします。対象となるユーザーについては、ロジックに沿ってアドオン アタッチメントを含む課題を作成します。それ以外の場合は、リンク マテリアルを作成します。ユーザーが課題を作成するコースの ID を把握しておく必要があります。通常は、使用するコースを指定するようユーザーにプロンプトを表示します。わかりやすくするため、この例ではハードコードされた値を使用します。

Python

# /webapp/coursework_routes.py
@app.route("/create-coursework-assignment")
def create_coursework_assignment():
  """
  Completes the assignment creation flow.
  """
  # ... Check that the user is signed in and get the Classroom service ...

  # Check whether the user can create add-on attachments.
  eligibility_response = (
      classroom_service.userProfiles()
      .checkUserCapability(
        userId="me",
        capability="CREATE_ADD_ON_ATTACHMENT",
        # The previewVersion is necessary while the method is available in the
        # Workspace Developer Preview Program.
        previewVersion="V1_20240930_PREVIEW",
      ).execute()
  )
  is_create_attachment_eligible = eligibility_response.get("allowed")

  if is_create_attachment_eligible:
    # See the "Create an assignment with add-on attachment for eligible users" section for implementation.
  if not is_create_attachment_eligible:
    # See the "Create a Link Material" section for implementation.

対象ユーザー向けにアドオンの添付ファイルを含む課題を作成する

お客様がアドオン アタッチメントを作成できる場合は、次の手順を行います。

  1. API リクエストを送信して、添付ファイルなしで Google Classroom に courseWork 課題を作成します。
  2. 新しく作成したアサインメントの id を抽出します。
  3. 新しい CourseWork AddOnAttachment を作成します。
  4. Google Classroom で新しく作成された課題にアドオンの添付ファイルを作成するリクエストを送信します。

Python

# The ID of the course to which the assignment will be added.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.

# /webapp/coursework_routes.py
if is_create_attachment_eligible:
  # Create an assignment.
  coursework = {
      "title": "My CourseWork Assignment with Add-on Attachment",
      "description": "Created using the Classroom CourseWork API.",
      "workType": "ASSIGNMENT",
      "state": "DRAFT",  # Set to 'PUBLISHED' to assign to students.
  }

  # Issue a request to create the assignment.
  create_assignment_response = (
      classroom_service.courses()
      .courseWork()
      .create(courseId=course_id, body=coursework)
      .execute()
  )

  # Create an add-on attachment that links to the selected content and
  # associate it with the new assignment.
  content_url = flask.url_for(
      "example_coursework_assignment",
      assignment_type="add-on-attachment",
      _scheme="https",
      _external=True,
  )

  # Construct an AddOnAttachment instance.
  attachment = {
      "teacherViewUri": {"uri": content_url},
      "studentViewUri": {"uri": content_url},
      "title": f'Test Attachment for Assignment {create_assignment_response.get("id")}',
  }

  # Issue a request to create the attachment.
  add_on_attachment_response = (
      classroom_service.courses()
      .courseWork()
      .addOnAttachments()
      .create(
          courseId=course_id,
          itemId=create_assignment_response.get("id"),  # ID of the new assignment.
          body=attachment,
      )
      .execute()
  )

ユーザーがアドオン アタッチメントを作成できない場合は、代わりにリンク マテリアルを作成します。手順は次のとおりです。

Python

# The ID of the course to which the assignment will be added.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.

if not is_create_attachment_eligible:
    coursework = {
        "title": "My CourseWork Assignment with Link Material",
        "description": "Created using the Classroom CourseWork API.",
        "workType": "ASSIGNMENT",
        "state": "DRAFT",  # Set to 'PUBLISHED' to assign to students.
        # Specify the URL for your content as a Link Material.
        "materials": [
            {
                "link": {
                    "url": flask.url_for(
                        "example_coursework_assignment",
                        assignment_type="link-material",
                        _scheme="https",
                        _external=True,
                    )
                }
            }
        ],
    }

    # Issue a request to create the assignment.
    assignment_response = (
        classroom_service.courses()
        .courseWork()
        .create(courseId=course_id, body=coursework)
        .execute()
    )

作成済みの課題を変更する

ストリーム アイテムの作成者に関わらず、アドオンの添付ファイルが 1 つ以上含まれている Google Classroom ストリーム アイテムには、アクセス、変更、提出、再利用、返却を行うことができます。ストリーム アイテムは、AnnouncementCourseWork 課題、CourseWorkMaterial です。

これを示すために、特定のストリーミング アイテムを変更するルートを追加します。この方法では、API を使用して作成したストリーム アイテムと、Google Classroom UI を使用して教師が作成したストリーム アイテムにアクセスして変更できることを確認します。

このチュートリアルで最初に編集したウェブページに、リンクまたはボタンをもう 1 つ追加します。CourseWork アサインを変更する新しいルートが開きます。

Python

提供されている Python の例では、このチュートリアルの前半で変更した /index ルートを変更します。

<!-- /webapp/templates/index.html -->
<a href="modify-coursework-assignment.html">Create a CourseWork Assignment</a>

CourseWork 関連のルートを処理する新しいルートを作成します。これは、提供されている例の coursework_routes.py ファイルにあります。

# Check that the user is signed in.
credentials = get_credentials()

if not credentials:
  return start_auth_flow("coursework_assignment_callback")

# Get the Google Classroom service.
classroom_service = get_classroom_service()

# The ID of the course to which the assignment will be added.
# Ordinarily, you'll prompt the user to specify which course to use. For
# simplicity, we use a hard-coded value in this example.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.
assignment_id = 1234567890  # TODO(developer) Replace with an actual assignment ID.

# Retrieve details about the CourseWork assignment.
get_coursework_response = (
    classroom_service.courses()
    .courseWork()
    .get(courseId=course_id, id=assignment_id)
    .execute()
)

# Alter the current title.
assignment_title = f"{get_coursework_response.get('title')} (Modified by API request)"

# Issue a request to modify the assignment.
modify_coursework_response = (
    classroom_service.courses()
    .courseWork()
    .patch(
        courseId=course_id,
        id=assignment_id,
        updateMask="title",
        body={"title": assignment_title},
    )
    .execute()
)

アドオンをテストする

わかりやすくするため、ここで提供する例では、コースと課題の識別子をハードコードしています。これらの識別子は、教師の認証情報を使用して、courses リソースと courseWork リソースの get メソッドと list メソッドにリクエストを送信することで取得できます。また、courseWork 課題を作成するときにレスポンスで返されます。

サーバーを実行し、インデックス ページに移動して、Google Workspace for Education Teaching & Learning または Plus ライセンスのない教師ユーザーとしてログインします。テストドメインの管理コンソールから、ユーザーのライセンス ステータスを切り替えることができます。[Create a CourseWork Assignment] ボタンをクリックし、Google Classroom UI を開いて、リンク マテリアルの添付ファイルを含む課題が作成されたことを確認します。添付ファイルには、リンクされたウェブページのタイトルと URL が表示されます。

アドオン添付ファイルの作成をテストする

インデックス ページに戻り、Google Workspace for Education Teaching and Learning または Plus ライセンスを持つ教師ユーザーとしてログインします。[Create a CourseWork Assignment] ボタンをクリックし、Google Classroom UI を開いて、アドオン アタッチメントを含む課題が作成されたことを確認します。アタッチメントには、アドオン アプリケーションの名前と、コードで指定したタイトルが表示されます。

課題の変更をテストする

インデックス ページに戻り、Teaching and Learning または Plus ライセンスを持つ教師ユーザーとしてログインしていることを確認します。[CourseWork 課題を変更] ボタンをクリックし、Google Classroom の UI に戻って、課題のタイトルが変更されていることを確認します。

これで、チュートリアル シリーズを完了しました。