Administración de trabajos del curso

La app de Classroom admite tres tipos de elementos de transmisión: CourseWork, CourseWorkMaterials y Announcements. En esta guía, se describe cómo administrar CourseWork, pero las APIs de todos los elementos de transmisión son similares. Consulta los recursos de la API para obtener más información sobre los tipos de elementos de transmisión y sus diferencias.

El recurso CourseWork representa un elemento de trabajo que se asignó a los estudiantes en un curso en particular, incluidos los materiales y detalles adicionales, como la fecha límite o la puntuación máxima. Hay cuatro subtipos de CourseWork: tareas, tareas de cuestionarios, preguntas de respuesta corta y preguntas de opción múltiple. La API de Classroom admite tres de estos subtipos: tareas, preguntas de respuesta corta y preguntas de opción múltiple. Estos tipos se representan con el campo CourseWork.workType.

Además del recurso CourseWork, puedes administrar el trabajo completado con el recurso StudentSubmission.

Crea trabajos del curso

CourseWork solo se puede crear en nombre del profesor del curso. Si intentas crear CourseWork en nombre de un estudiante o un administrador de dominio que no es profesor del curso, se producirá un error PERMISSION_DENIED. Consulta Tipos de usuarios para obtener más información sobre los diferentes roles en Classroom.

Cuando creas CourseWork con el método courses.courseWork.create, puedes adjuntar vínculos como materials, como se muestra en el siguiente código de ejemplo:

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

Los campos title y workType son obligatorios. Todos los demás campos son opcionales. Si no se especifica state, CourseWork se crea en un estado de borrador.

Usa un recurso de vínculo con un objetivo url especificado para incluir materiales vinculados en el CourseWork. Classroom recupera automáticamente la URL de la imagen de miniatura (thumbnailUrl) y title. La API de Classroom también admite de forma nativa los materiales de Google Drive y YouTube, que se pueden incluir con un recurso DriveFile o un recurso YouTubeVideo de manera similar.

Para especificar una fecha límite, establece los campos dueDate y dueTime en la hora UTC correspondiente. La fecha límite debe ser futura.

La respuesta CourseWork incluye un identificador asignado por el servidor que se puede usar para hacer referencia a la asignación en otras solicitudes a la API.

Cómo recuperar trabajos del curso

Puedes recuperar CourseWork en nombre de los estudiantes y profesores del curso correspondiente. También puedes recuperar CourseWork en nombre de los administradores de dominios, incluso si no son profesores del curso. Para recuperar un CourseWork específico, usa courses.courseWork.get. Para recuperar todos los CourseWork (de forma opcional, que coincidan con algunos criterios), usa courses.courseWork.list.

El alcance requerido depende del rol que tenga el usuario solicitante en el curso. Si el usuario es estudiante, usa uno de los siguientes permisos:

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

Si el usuario es profesor o administrador de dominio, usa uno de los siguientes alcances:

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

Tener permiso para recuperar un CourseWork no implica permisos para acceder a los materiales ni a sus metadatos. En la práctica, esto significa que un administrador puede no ver el título de un archivo adjunto de Drive si no es miembro del curso.

Administra las respuestas de los estudiantes

Un recurso StudentSubmission representa el trabajo que realiza un estudiante para un CourseWork. El recurso incluye metadatos relacionados con el trabajo, como el estado y la calificación. Se crea un StudentSubmission de forma implícita para cada estudiante cuando se crea un CourseWork nuevo.

En las siguientes secciones, se explican las acciones comunes que administran las respuestas de los estudiantes.

Cómo recuperar las respuestas de los estudiantes

Los estudiantes pueden recuperar sus propios envíos, los profesores pueden recuperar los envíos de todos los estudiantes de sus cursos, y los administradores de dominios pueden recuperar todos los envíos de todos los estudiantes de su dominio. A cada StudentSubmission se le asigna un identificador. Si conoces el identificador, usa courses.courseWork.studentSubmissions.get para recuperar el envío.

Usa el método courses.courseWork.studentSubmissions.list para obtener todos los recursos StudentSubmission que coincidan con algunos criterios, como se muestra en el siguiente ejemplo:

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

Para recuperar los recursos StudentSubmission que pertenecen a un estudiante en particular, especifica el parámetro userId, como se muestra en el siguiente ejemplo:

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());
    }
  }
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")

Los estudiantes se identifican por el ID único o la dirección de correo electrónico, como se representa en el recurso Student. El usuario actual también puede hacer referencia a su propio ID con la sigla "me".

También es posible recuperar las entregas de los estudiantes de todas las tareas de un curso. Para ello, usa la literal "-" como courseWorkId, como se muestra en el siguiente ejemplo:

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

El alcance requerido depende del rol que tenga el usuario solicitante en el curso. Si el usuario es profesor o administrador de dominio, usa el siguiente permiso:

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

Si el usuario es estudiante, usa el siguiente permiso:

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

Tener permiso para recuperar un StudentSubmission no implica permisos para acceder a los archivos adjuntos ni a sus metadatos. En la práctica, esto significa que es posible que un administrador no vea el título de un archivo de Drive adjunto si no es miembro del curso.

Cómo agregar archivos adjuntos a una respuesta de un estudiante

Para adjuntar vínculos a una entrega de un estudiante, agrega un recurso Link, DriveFile o YouTubeVideo. Esto se hace con courses.courseWork.studentSubmissions.modifyAttachments, como se muestra en el siguiente ejemplo:

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

El url de destino define un archivo adjunto Link. Classroom recupera automáticamente la title y la imagen en miniatura (thumbnailUrl). Consulta Material para obtener información sobre los materiales que se pueden adjuntar a StudentSubmissions.

Solo el profesor del curso o el estudiante propietario puede modificar el StudentSubmission. Solo puedes adjuntar Materials si el CourseWorkType de StudentSubmission es ASSIGNMENT.

El alcance requerido depende del rol que tenga el usuario solicitante en el curso. Si el usuario es profesor, usa el siguiente permiso:

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

Si el usuario es estudiante, usa el siguiente permiso:

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