課題の管理

Classroom アプリは、CourseWorkCourseWorkMaterialsAnnouncements の 3 種類のストリーミング アイテムをサポートしています。このガイドでは CourseWork の管理方法について説明しますが、すべてのストリーム アイテムの API は類似しています。ストリーム アイテムの種類とその違いの詳細については、API リソースをご覧ください。

CourseWork リソースは、特定のコース内の生徒に割り当てられた作業項目を表します。これには、追加の資料や、期限や最大スコアなどの詳細が含まれます。CourseWork には、課題テスト付きの課題記述式の質問多肢選択式の質問の 4 つのサブタイプがあります。Classroom API は、課題、記述式の質問、多肢選択式の質問の 3 つのサブタイプをサポートしています。これらのタイプは CourseWork.workType フィールドで表されます。

CourseWork リソースに加えて、完了した作業は StudentSubmission リソースで管理できます。

課題を作成

CourseWork は、コースの教師に代わって作成のみ可能です。生徒またはコースの教師ではないドメイン管理者に代わって CourseWork を作成しようとすると、PERMISSION_DENIED エラーが発生します。Classroom のさまざまなロールについて詳しくは、ユーザータイプをご覧ください。

courses.courseWork.create メソッドを使用して CourseWork を作成する場合は、次のサンプルコードに示すように、リンクを materials として接続できます。

Java

classroom/snippets/src/main/java/CreateCourseWork.java
CourseWork courseWork = null;
try {
  // Create a link to add as a material on course work.
  Link articleLink =
      new Link()
          .setTitle("SR-71 Blackbird")
          .setUrl("https://www.lockheedmartin.com/en-us/news/features/history/blackbird.html");

  // Create a list of Materials to add to course work.
  List<Material> materials = Arrays.asList(new Material().setLink(articleLink));

  /* Create new CourseWork object with the material attached.
  Set workType to `ASSIGNMENT`. Possible values of workType can be found here:
  https://developers.google.com/classroom/reference/rest/v1/CourseWorkType
  Set state to `PUBLISHED`. Possible values of state can be found here:
  https://developers.google.com/classroom/reference/rest/v1/courses.courseWork#courseworkstate */
  CourseWork content =
      new CourseWork()
          .setTitle("Supersonic aviation")
          .setDescription(
              "Read about how the SR-71 Blackbird, the world’s fastest and "
                  + "highest-flying manned aircraft, was built.")
          .setMaterials(materials)
          .setWorkType("ASSIGNMENT")
          .setState("PUBLISHED");

  courseWork = service.courses().courseWork().create(courseId, content).execute();

  /* Prints the created courseWork. */
  System.out.printf("CourseWork created: %s\n", courseWork.getTitle());
} catch (GoogleJsonResponseException e) {
  // TODO (developer) - handle error appropriately
  GoogleJsonError error = e.getDetails();
  if (error.getCode() == 404) {
    System.out.printf("The courseId does not exist: %s.\n", courseId);
  } else {
    throw e;
  }
  throw e;
} catch (Exception e) {
  throw e;
}
return courseWork;

Python

classroom/snippets/classroom_create_coursework.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def classroom_create_coursework(course_id):
  """
  Creates the coursework the user has access to.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """

  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member

  try:
    service = build("classroom", "v1", credentials=creds)
    coursework = {
        "title": "Ant colonies",
        "description": """Read the article about ant colonies
                              and complete the quiz.""",
        "materials": [
            {"link": {"url": "http://example.com/ant-colonies"}},
            {"link": {"url": "http://example.com/ant-quiz"}},
        ],
        "workType": "ASSIGNMENT",
        "state": "PUBLISHED",
    }
    coursework = (
        service.courses()
        .courseWork()
        .create(courseId=course_id, body=coursework)
        .execute()
    )
    print(f"Assignment created with ID {coursework.get('id')}")
    return coursework

  except HttpError as error:
    print(f"An error occurred: {error}")
    return error


if __name__ == "__main__":
  # Put the course_id of course whose coursework needs to be created,
  # the user has access to.
  classroom_create_coursework(453686957652)

title フィールドと workType フィールドは必須です。それ以外のフィールドはすべて省略可能です。state が指定されていない場合、CourseWork はドラフト状態として作成されます。

指定したターゲット url を使用してリンク リソースを使用し、リンクされたマテリアルを CourseWork に含めます。Classroom は、title とサムネイル画像の URL(thumbnailUrl)を自動的に取得します。Classroom API は、Google ドライブと YouTube の教材もネイティブにサポートしています。これらの教材は、DriveFile リソースまたは YouTubeVideo リソースに同様の方法で含めることができます。

期限を指定するには、dueDate フィールドと dueTime フィールドを対応する UTC 時間に設定します。期限には将来の日付を指定してください。

CourseWork レスポンスには、他の API リクエストで割り当てを参照するために使用できるサーバー割り当て ID が含まれています。

課題を取得する

対応するコースの生徒と教師に代わって CourseWork を取得できます。ドメイン管理者がコースの教師でない場合でも、ドメイン管理者に代わって CourseWork を取得することもできます。特定の CourseWork を取得するには、courses.courseWork.get を使用します。すべての CourseWork を取得するには(一部の条件を一致させる場合)、courses.courseWork.list を使用します。

必要なスコープは、リクエスト元のユーザーがコースで持っているロールによって異なります。ユーザーが生徒の場合は、次のいずれかのスコープを使用します。

  • https://www.googleapis.com/auth/classroom.coursework.me.readonly
  • https://www.googleapis.com/auth/classroom.coursework.me

ユーザーが教師またはドメイン管理者の場合は、次のいずれかのスコープを使用します。

  • https://www.googleapis.com/auth/classroom.coursework.students.readonly
  • https://www.googleapis.com/auth/classroom.coursework.students

CourseWork を取得する権限があっても、マテリアルまたはマテリアルのメタデータにアクセスする権限が付与されているわけではありません。つまり、管理者がコースのメンバーでない場合、添付されたドライブ ファイルのタイトルが表示されないことがあります。

生徒の回答を管理する

StudentSubmission リソースは、生徒が CourseWork に対して行った作業を表します。このリソースには、作業のステータスや評価など、作業に関連するメタデータが含まれます。新しい CourseWork が作成されると、生徒ごとに StudentSubmission が暗黙的に作成されます。

以降のセクションでは、生徒の回答を管理する一般的な操作について説明します。

生徒の回答を取得する

生徒は自分の提出物を取得できます。教師はコース内のすべての生徒の提出物を取得できます。ドメイン管理者は、ドメイン内のすべての生徒のすべての提出物を取得できます。各 StudentSubmission には識別子が割り当てられます。ID がわかっている場合は、courses.courseWork.studentSubmissions.get を使用して送信を取得します。

次のサンプルに示すように、courses.courseWork.studentSubmissions.list メソッドを使用して、特定の条件に一致するすべての StudentSubmission リソースを取得します。

Java

classroom/snippets/src/main/java/ListSubmissions.java
List<StudentSubmission> studentSubmissions = new ArrayList<>();
String pageToken = null;

try {
  do {
    ListStudentSubmissionsResponse response =
        service
            .courses()
            .courseWork()
            .studentSubmissions()
            .list(courseId, courseWorkId)
            .setPageToken(pageToken)
            .execute();

    /* Ensure that the response is not null before retrieving data from it to avoid errors. */
    if (response.getStudentSubmissions() != null) {
      studentSubmissions.addAll(response.getStudentSubmissions());
      pageToken = response.getNextPageToken();
    }
  } while (pageToken != null);

  if (studentSubmissions.isEmpty()) {
    System.out.println("No student submission found.");
  } else {
    for (StudentSubmission submission : studentSubmissions) {
      System.out.printf(
          "Student id (%s), student submission id (%s)\n",
          submission.getUserId(), submission.getId());
    }
  }
} catch (GoogleJsonResponseException e) {
  // TODO (developer) - handle error appropriately
  GoogleJsonError error = e.getDetails();
  if (error.getCode() == 404) {
    System.out.printf(
        "The courseId (%s) or courseWorkId (%s) does not exist.\n", courseId, courseWorkId);
  } else {
    throw e;
  }
} catch (Exception e) {
  throw e;
}
return studentSubmissions;

Python

classroom/snippets/classroom_list_submissions.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def classroom_list_submissions(course_id, coursework_id):
  """
  Creates the courses the user has access to.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """

  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member
  submissions = []
  page_token = None

  try:
    service = build("classroom", "v1", credentials=creds)
    while True:
      coursework = service.courses().courseWork()
      response = (
          coursework.studentSubmissions()
          .list(
              pageToken=page_token,
              courseId=course_id,
              courseWorkId=coursework_id,
              pageSize=10,
          )
          .execute()
      )
      submissions.extend(response.get("studentSubmissions", []))
      page_token = response.get("nextPageToken", None)
      if not page_token:
        break

    if not submissions:
      print("No student submissions found.")

    print("Student Submissions:")
    for submission in submissions:
      print(
          "Submitted at:"
          f"{(submission.get('id'), submission.get('creationTime'))}"
      )

  except HttpError as error:
    print(f"An error occurred: {error}")
    submissions = None
  return submissions


if __name__ == "__main__":
  # Put the course_id and coursework_id of course whose list needs to be
  # submitted.
  classroom_list_submissions(453686957652, 466086979658)

次のサンプルに示すように、userId パラメータを指定して、特定の生徒に属する StudentSubmission リソースを取得します。

Java

classroom/snippets/src/main/java/ListStudentSubmissions.java
List<StudentSubmission> studentSubmissions = new ArrayList<>();
String pageToken = null;

try {
  do {
    // Set the userId as a query parameter on the request.
    ListStudentSubmissionsResponse response =
        service
            .courses()
            .courseWork()
            .studentSubmissions()
            .list(courseId, courseWorkId)
            .setPageToken(pageToken)
            .set("userId", userId)
            .execute();

    /* Ensure that the response is not null before retrieving data from it to avoid errors. */
    if (response.getStudentSubmissions() != null) {
      studentSubmissions.addAll(response.getStudentSubmissions());
      pageToken = response.getNextPageToken();
    }
  } while (pageToken != null);

  if (studentSubmissions.isEmpty()) {
    System.out.println("No student submission found.");
  } else {
    for (StudentSubmission submission : studentSubmissions) {
      System.out.printf("Student submission: %s.\n", submission.getId());
    }
  }

Python

classroom/snippets/classroom_list_student_submissions.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def classroom_list_student_submissions(course_id, coursework_id, user_id):
  """
  Creates the courses the user has access to.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """

  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member
  submissions = []
  page_token = None

  try:
    service = build("classroom", "v1", credentials=creds)
    while True:
      coursework = service.courses().courseWork()
      response = (
          coursework.studentSubmissions()
          .list(
              pageToken=page_token,
              courseId=course_id,
              courseWorkId=coursework_id,
              userId=user_id,
          )
          .execute()
      )
      submissions.extend(response.get("studentSubmissions", []))
      page_token = response.get("nextPageToken", None)
      if not page_token:
        break

    if not submissions:
      print("No student submissions found.")

    print("Student Submissions:")
    for submission in submissions:
      print(
          "Submitted at:"
          f"{(submission.get('id'), submission.get('creationTime'))}"
      )

  except HttpError as error:
    print(f"An error occurred: {error}")
  return submissions


if __name__ == "__main__":
  # Put the course_id, coursework_id and user_id of course whose list needs
  # to be submitted.
  classroom_list_student_submissions(453686957652, 466086979658, "me")

生徒は、Student リソースに表示される一意の ID またはメールアドレスで識別されます。現在のユーザーは、"me" の省略形を使用して自分の ID を参照することもできます。

コース内のすべての課題の生徒の提出物を取得することもできます。これを行うには、次のサンプルに示すように、courseWorkId としてリテラル "-" を使用します。

Java

service.courses().courseWork().studentSubmissions()
    .list(courseId, "-")
    .set("userId", userId)
    .execute();

Python

service.courses().courseWork().studentSubmissions().list(
    courseId=<course ID or alias>,
    courseWorkId='-',
    userId=<user ID>).execute()

必要なスコープは、リクエスト元のユーザーがコースで持っているロールによって異なります。ユーザーが教師またはドメイン管理者の場合は、次のスコープを使用します。

  • https://www.googleapis.com/auth/classroom.coursework.students.readonly
  • https://www.googleapis.com/auth/classroom.coursework.students

ユーザーが生徒の場合は、次のスコープを使用します。

  • https://www.googleapis.com/auth/classroom.coursework.me.readonly
  • https://www.googleapis.com/auth/classroom.coursework.me

StudentSubmission を取得する権限があっても、添付ファイルまたは添付ファイルのメタデータにアクセスする権限が付与されているわけではありません。つまり、管理者がコースのメンバーでない場合、添付されたドライブ ファイルのタイトルが表示されないことがあります。

生徒の回答に添付ファイルを追加する

生徒の提出物にリンクを添付するには、LinkDriveFile、または YouTubeVideo リソースを添付します。これは、次のサンプルに示すように courses.courseWork.studentSubmissions.modifyAttachments で行います。

Java

classroom/snippets/src/main/java/ModifyAttachmentsStudentSubmission.java
StudentSubmission studentSubmission = null;
try {
  // Create ModifyAttachmentRequest object that includes a new attachment with a link.
  Link link = new Link().setUrl("https://en.wikipedia.org/wiki/Irrational_number");
  Attachment attachment = new Attachment().setLink(link);
  ModifyAttachmentsRequest modifyAttachmentsRequest =
      new ModifyAttachmentsRequest().setAddAttachments(Arrays.asList(attachment));

  // The modified studentSubmission object is returned with the new attachment added to it.
  studentSubmission =
      service
          .courses()
          .courseWork()
          .studentSubmissions()
          .modifyAttachments(courseId, courseWorkId, id, modifyAttachmentsRequest)
          .execute();

  /* Prints the modified student submission. */
  System.out.printf(
      "Modified student submission attachments: '%s'.\n",
      studentSubmission.getAssignmentSubmission().getAttachments());
} catch (GoogleJsonResponseException e) {
  // TODO (developer) - handle error appropriately
  GoogleJsonError error = e.getDetails();
  if (error.getCode() == 404) {
    System.out.printf(
        "The courseId (%s), courseWorkId (%s), or studentSubmissionId (%s) does "
            + "not exist.\n",
        courseId, courseWorkId, id);
  } else {
    throw e;
  }
} catch (Exception e) {
  throw e;
}
return studentSubmission;

Python

classroom/snippets/classroom_add_attachment.py
def classroom_add_attachment(course_id, coursework_id, submission_id):
  """
  Adds attachment to existing course with specific course_id.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """
  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member
  request = {
      "addAttachments": [
          {"link": {"url": "http://example.com/quiz-results"}},
          {"link": {"url": "http://example.com/quiz-reading"}},
      ]
  }

  try:
    service = build("classroom", "v1", credentials=creds)
    while True:
      coursework = service.courses().courseWork()
      coursework.studentSubmissions().modifyAttachments(
          courseId=course_id,
          courseWorkId=coursework_id,
          id=submission_id,
          body=request,
      ).execute()

  except HttpError as error:
    print(f"An error occurred: {error}")


if __name__ == "__main__":
  # Put the course_id, coursework_id and submission_id of course in which
  # attachment needs to be added.
  classroom_add_attachment("course_id", "coursework_id", "me")

Link アタッチメントはターゲット url によって定義されます。Classroom は title とサムネイル画像(thumbnailUrl)を自動的に取得します。StudentSubmissions にアタッチできる教材については、Material をご覧ください。

StudentSubmission を変更できるのは、コースの教師またはその所有者である生徒のみです。StudentSubmissionCourseWorkTypeASSIGNMENT の場合にのみ、Materials を接続できます。

必要なスコープは、リクエスト元のユーザーがコースで持っているロールによって異なります。ユーザーが教師の場合は、次のスコープを使用します。

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

ユーザーが生徒の場合は、次のスコープを使用します。

  • https://www.googleapis.com/auth/classroom.coursework.me