課題の管理

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 リクエストで割り当てを参照するために使用できるサーバー割り当ての識別子が含まれています。

課題を取得する

対応するコースの生徒と教師に代わって 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 には識別子が割り当てられます。識別子がわかっている場合は、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 は、コースの教師または所有する生徒のみが変更できます。Materials をアタッチできるのは、StudentSubmissionCourseWorkTypeASSIGNMENT の場合のみです。

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

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

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

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