Gérer les devoirs et les notes

L'interface utilisateur de Classroom accepte cinq types de travaux et devoirs: Devoirs, Devoirs avec quiz, Questions à réponse courte, Questions à choix multiples et Supports de cours. L'API Classroom est actuellement compatible avec trois de ces types, appelés CourseWorkType: Devoirs, les questions à réponse courte et les questions à choix multiples.

Materials à des ressources CourseWorkType: devoirs, questions à réponse courte et questions à choix multiples.

Pour accéder à cette fonctionnalité, vous pouvez utiliser la ressource courseWork, qui représente un devoir ou une question attribués aux élèves d'un cours particulier, y compris tous les supports et détails supplémentaires, tels que la date limite ou le score maximal.

En plus de la ressource CourseWork, vous pouvez gérer les devoirs terminés avec la ressource StudentSubmission. Les sections suivantes les décrivent plus en détail.

Créer des devoirs

Les devoirs peuvent être créés uniquement au nom des enseignants du cours. Si vous tentez de créer des devoirs dans un cours pour le compte d'un élève, une erreur 403 PERMISSION_DENIED est générée. De même, les administrateurs de domaine ne peuvent pas non plus créer d'attributions pour des cours qu'ils n'enseignent pas. Toute tentative de le faire via l'API entraîne également une erreur 403 PERMISSION_DENIED.

Lorsque vous créez des attributions à l'aide de la méthode courses.courseWork.create, vous pouvez joindre des liens en tant que materials, comme indiqué dans l'exemple de code ci-dessous:

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)

Le résultat inclut un identifiant attribué par le serveur qui peut être utilisé pour référencer l'attribution dans d'autres requêtes API.

Pour inclure des supports de cours associés dans un devoir créé via l'API Classroom, utilisez une ressource Lien, en indiquant l'URL cible. Classroom récupère automatiquement le titre et la miniature. L'API Classroom est également compatible de manière native avec les supports Google Drive et YouTube, qui peuvent être inclus de la même manière dans une ressource DriveFile ou une ressource YouTubeVideo.

Pour spécifier une date limite, définissez les champs dueDate et dueTime sur l'heure UTC correspondante. La date limite doit être située dans le futur.

Récupérer les devoirs et les questions

Vous pouvez récupérer les devoirs et les questions des élèves et des enseignants du cours correspondant ou par un administrateur de domaine. Pour récupérer un devoir ou une question spécifique, utilisez courses.courseWork.get. Pour récupérer tous les devoirs ou questions (correspondant éventuellement à certains critères), utilisez courses.courseWork.list.

Le champ d'application requis dépend du rôle que possède l'utilisateur à l'origine de la demande dans le cours. Si l'utilisateur est un élève, utilisez l'un des champs d'application suivants:

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

Si l'utilisateur est un enseignant ou un administrateur de domaine, utilisez l'un des champs d'application suivants:

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

Avoir l'autorisation de récupérer un devoir ou une question n'implique pas l'autorisation d'accéder à des contenus ou à leurs métadonnées. En pratique, cela signifie qu'un administrateur peut ne pas voir le titre d'un fichier Drive joint s'il n'est pas membre du cours. Si vous souhaitez autoriser les administrateurs à accéder aux fichiers utilisateur, consultez le guide sur la délégation au niveau du domaine.

Gérer les réponses des élèves

Une ressource StudentSubmission représente le travail effectué et la note d'un élève pour un devoir ou une question. Une ressource StudentSubmission est créée implicitement pour chaque élève lorsqu'une question ou un devoir est créé.

Les sections suivantes expliquent les actions courantes qui permettent de gérer les réponses des élèves.

Récupérer les réponses des élèves

Les élèves peuvent récupérer leurs propres devoirs, les enseignants peuvent récupérer les devoirs de tous les élèves de leurs cours et les administrateurs de domaine peuvent récupérer tous les devoirs de tous les élèves de leur domaine. Un identifiant est attribué à chaque élève. Si vous connaissez cet identifiant, utilisez courses.courseWork.studentSubmissions.get pour le récupérer.

Utilisez la méthode courses.courseWork.studentSubmissions.list pour obtenir les ressources StudentSubmission correspondant à certains critères, comme illustré dans l'exemple suivant:

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)

Récupérez les ressources StudentSubmission appartenant à un élève particulier en spécifiant le paramètre userId, comme indiqué dans l'exemple suivant:

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

Les élèves sont identifiés par l'identifiant unique ou l'adresse e-mail de l'utilisateur, tel qu'indiqué par le SDK Admin de Google. L'utilisateur actuel peut également faire référence à son propre ID à l'aide du raccourci "me".

Il est également possible de recevoir des devoirs pour tous les devoirs d'un cours. Pour ce faire, utilisez le littéral "-" comme courseWorkId, comme illustré dans l'exemple suivant:

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

Le champ d'application requis dépend du rôle que possède l'utilisateur à l'origine de la demande dans le cours. Utilisez le champ d'application suivant si l'utilisateur est un enseignant ou un administrateur de domaine:

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

Utilisez le champ d'application suivant si l'utilisateur est un élève:

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

L'autorisation de récupérer le travail d'un élève n'implique pas l'autorisation d'accéder aux pièces jointes ou aux métadonnées associées. En pratique, cela signifie qu'un administrateur peut ne pas voir le titre d'un fichier Drive joint s'il n'est pas membre du cours. Si vous souhaitez autoriser les administrateurs à accéder aux fichiers des utilisateurs, consultez le guide de délégation au niveau du domaine.

Ajouter des pièces jointes à une réponse d'élève

Vous pouvez joindre des liens à un devoir d'élève en joignant une ressource Link, DriveFile ou YouTubeVideo. Pour ce faire, utilisez courses.courseWork.studentSubmissions.modifyAttachments, comme illustré dans l'exemple suivant:

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

Une pièce jointe de lien est définie par l'URL cible. Classroom extrait automatiquement le titre et la vignette. Pour en savoir plus sur les autres documents, consultez leurs pages de référence respectives.

Le StudentSubmission ne peut être modifié que par un enseignant de cours ou par l'élève auquel il appartient. Vous ne pouvez joindre un élément Materials que si l'élément CourseWorkType du devoir envoyé par l'élève est ASSIGNMENT.

Le champ d'application requis dépend du rôle que possède l'utilisateur à l'origine de la demande dans le cours. Utilisez le champ d'application suivant si l'utilisateur est un enseignant:

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

Utilisez le champ d'application suivant si l'utilisateur est un élève:

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

Gérer l'état des réponses des élèves

La réponse d'un élève peut être annulée, remise ou rendue. Le champ d'état dans StudentSubmission indique l'état actuel. Pour modifier l'état, appelez l'une des méthodes suivantes:

Toutes ces méthodes utilisent un corps vide. Exemple :

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

Seul l'élève propriétaire d'une StudentSubmission peut la rendre ou la récupérer. Seul un envoi remis peut être récupéré. Les enseignants de cours ne peuvent renvoyer qu'un objet StudentSubmission dont l'état est rendu.

Noter les réponses des élèves

La ressource StudentSubmission comporte deux champs permettant de stocker les notes : assignedGrade, qui est la note transmise aux élèves, et draftGrade, une note provisoire visible uniquement par les enseignants. Ces champs sont mis à jour à l'aide de courses.courseWork.studentSubmissions.patch avec un masque de champ contenant les champs appropriés, comme illustré dans l'exemple suivant.

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

Avec l'interface utilisateur Classroom, les enseignants ne peuvent pas attribuer de note tant qu'ils n'ont pas enregistré une note temporaire. La note attribuée peut ensuite être renvoyée à un élève. Les applications doivent émuler ce comportement. Votre application peut noter le devoir d'un élève de deux manières:

  • Attribuez uniquement draftGrade. Cela permet, par exemple, de permettre à l'enseignant de vérifier manuellement les notes avant de les finaliser. Les élèves ne peuvent pas voir les notes temporaires.

  • Attribuez les draftGrade et l'assignedGrade pour noter complètement un devoir.

Lister les notes attribuées

Vous pouvez répertorier toutes les notes pour un élément de devoir particulier en explorant l'objet de réponse de la méthode 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'))}")