管理課程作業和成績

Classroom UI 支援五種課堂作業類型:作業、 測驗作業、簡答題、選擇題及 教材。Classroom API 目前支援這三種, 在 API 中稱為 CourseWorkType:指派作業、簡答題 問題和選擇題

如要使用這項功能,您可以使用 CourseWork 資源 ,代表已指派給學生的「作業」或「問題」 包括任何補充教材和細節,例如特定課程的截止日期 日期或最高分數

除了 CourseWork 資源外,您也可以管理已完成的作業 使用 StudentSubmission 資源。以下各節將說明這些 一起來看看吧

建立作業

「只能」代表課程的老師建立作業, 試圖代表學生在課程中建立作業時,結果將 在 403 PERMISSION_DENIED 錯誤發生時。同樣地,網域管理員也無法建立 非教授/企圖透過 API 完成的課程作業 也會產生 403 PERMISSION_DENIED 錯誤。

使用 courses.courseWork.create 方法建立指派作業時, 可以以 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)

結果含有伺服器指派的 ID,可用於參照 其他 API 要求中的指派。

如要在透過 Classroom API 建立的作業中加入連結教材,請按照下列步驟操作: 請使用連結資源,並將 目標網址Classroom 會自動擷取標題和縮圖圖片, Classroom API 也內建支援 Google 雲端硬碟和 YouTube 教材, 隨附於 DriveFile 資源,或 YouTubeVideo 資源

如要指定截止日期,請將 dueDatedueTime 欄位設為 對應的世界標準時間截止日必須設在未來。

擷取作業和問題

您可以擷取下列學生和老師的作業和問題: 課程或網域管理員。如果要擷取 作業或問題,請使用 course.courseWork.get。擷取全部 作業或問題 (也可選擇比對某些條件),再使用 courses.courseWork.list.

所需範圍取決於提出要求的使用者所具備的角色 稍後您會在 BigQueryML AutoML 和自訂訓練中使用這些模型如果使用者是學生,請使用以下任一範圍:

  • 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

擁有擷取作業或問題的權限並不表示 存取教材或素材中繼資料的權限。在實務上 在下列情況中,管理員可能不會看到附加雲端硬碟檔案的標題 非課程成員如要允許管理員存取使用者 檔案,請參閱全網域 委派 指南。

管理學生的答案

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)

透過下列方式擷取特定學生的 StudentSubmission 資源: 指定 userId 參數,如以下範例所示:

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")

學生會以使用者的專屬 ID 或電子郵件地址做為辨識依據, Google Admin SDK 傳回的字串。目前的使用者可能稱為自己的 使用 "me" 簡寫為 ID。

此外,系統也可能傳送以下課程的所有作業: 稍後您會在 BigQueryML AutoML 和自訂訓練中使用這些模型方法是使用常值 "-" 做為 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()

所需範圍取決於提出要求的使用者所具備的角色 稍後您會在 BigQueryML AutoML 和自訂訓練中使用這些模型如果使用者是老師或網域,請使用下列範圍 管理員:

  • 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

有權擷取學生繳交的作業並不暗示 存取附件或附件中繼資料的權限。實務上 這表示在遇到以下情況時,管理員可能不會看到 他們並非課程成員如要授予管理員存取權 使用者檔案,請參閱 全網域委派指南。

在學生回覆中新增附件

您可以在學生繳交的作業中附加 LinkDriveFileYouTubeVideo 資源。方法是使用 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")

連結附件是由目標網址定義;Classroom 會自動套用 擷取標題和縮圖圖片。如要瞭解其他資料,請前往 各自的參考頁面

StudentSubmission只能由課程老師或 擁有者。您只能在以下情況下附加 Materials: 學生繳交的作業中有 CourseWorkTypeASSIGNMENT

所需範圍取決於提出要求的使用者所具備的角色 稍後您會在 BigQueryML AutoML 和自訂訓練中使用這些模型如果使用者是老師,請使用下列範圍:

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

如果使用者是學生,請使用下列範圍:

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

管理學生回覆狀態

學生可能會取消繳交、繳交或發還作業。州/省欄位 位於 StudentSubmission 表示目前狀態。如要變更狀態,請呼叫 您可以選擇下列其中一種做法:

這些方法的主體皆為空白。範例:

Java

classroom/snippets/src/main/java/ReturnStudentSubmission.java
try {
  service
      .courses()
      .courseWork()
      .studentSubmissions()
      .classroomReturn(courseId, courseWorkId, id, null)
      .execute();
} 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;
}

Python

service.courses().courseWork().studentSubmission().turnIn(
    courseId=<course ID or alias>,
    courseWorkId=<courseWork ID>,
    id=<studentSubmission ID>,
    body={}).execute()

只有擁有StudentSubmission的學生才能繳交或收回作業。 只能收回已繳交的作業。課程老師只能發還 StudentSubmission處於「繳交」狀態。

批改學生的作答內容

StudentSubmission 資源有兩個用來儲存成績的欄位: assignedGrade,也就是向學生回報的成績,draftGrade, 只有老師才能查看暫定成績。這些欄位已更新 搭配欄位遮罩使用 courses.courseWork.studentSubmissions.patch 包含適當欄位,如以下範例所示。

Java

classroom/snippets/src/main/java/PatchStudentSubmission.java
StudentSubmission studentSubmission = null;
try {
  // Updating the draftGrade and assignedGrade fields for the specific student submission.
  StudentSubmission content =
      service
          .courses()
          .courseWork()
          .studentSubmissions()
          .get(courseId, courseWorkId, id)
          .execute();
  content.setAssignedGrade(90.00);
  content.setDraftGrade(80.00);

  // The updated studentSubmission object is returned with the new draftGrade and assignedGrade.
  studentSubmission =
      service
          .courses()
          .courseWork()
          .studentSubmissions()
          .patch(courseId, courseWorkId, id, content)
          .set("updateMask", "draftGrade,assignedGrade")
          .execute();

  /* Prints the updated student submission. */
  System.out.printf(
      "Updated student submission draft grade (%s) and assigned grade (%s).\n",
      studentSubmission.getDraftGrade(), studentSubmission.getAssignedGrade());
} 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

studentSubmission = {
  'assignedGrade': 99,
  'draftGrade': 80
}
service.courses().courseWork().studentSubmissions().patch(
    courseId=<course ID or alias>,
    courseWorkId=<courseWork ID>,
    id=<studentSubmission ID>,
    updateMask='assignedGrade,draftGrade',
    body=studentSubmission).execute()

老師在使用 Classroom UI 時才能指派成績 尚未儲存暫定成績即可將該成績發還給學生 學生。應用程式需要模擬這個行為。應用程式可以 為學生的作業評分的方法有兩種:

  • 僅指派 draftGrade。這項功能很實用 例如讓教師 先手動查看成績,然後再完成作業學生無法查看暫定成績。

  • 同時指派draftGradeassignedGrade,即可完全批改作業。

,瞭解如何調查及移除這項存取權。

列出指派的成績

如要列出特定課程作業的所有成績,請前往 courses.courseWork.studentSubmissions.list 方法的回應物件:

Java

classroom/snippets/src/main/java/ListStudentSubmissions.java
  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 submissions found.");
} else {
  for (StudentSubmission submission : studentSubmissions) {
    System.out.printf(
        "User ID %s, Assigned grade: %s\n",
        submission.getUserId(), submission.getAssignedGrade());
  }
}

Python

response = coursework.studentSubmissions().list(
    courseId=course_id,
    courseWorkId=coursework_id,
    pageSize=10).execute()
submissions.extend(response.get('studentSubmissions', []))

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

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