Archivos adjuntos de tipo de contenido

Esta es la cuarta explicación en los complementos de Classroom .

En esta explicación, interactuarás con la API de Google Classroom para crear archivos adjuntos. Proporcionas rutas para que los usuarios vean el contenido de los adjuntos. El las vistas difieren según el rol del usuario en la clase. En esta explicación, se abordan archivos adjuntos de tipo de contenido, que no requieren una entrega del estudiante.

En esta explicación, completarás lo siguiente:

  • Recupera y usa los siguientes parámetros de consulta de complementos:
    • addOnToken: Un token de autorización que se pasa a la detección de adjuntos Ver.
    • itemId: Es un identificador único para los cursos CourseWork, CourseWorkMaterial o Anuncio que recibe el archivo adjunto del complemento.
    • itemType: "courseWork" o "courseWorkMaterials" o "anuncio".
    • courseId: Es un identificador único para el curso de Google Classroom en en la que se crea la asignación.
    • attachmentId: Es un identificador único que Google Classroom asigna a un archivo adjunto del complemento después de su creación.
  • Implementar almacenamiento persistente para archivos adjuntos de tipo de contenido
  • Proporciona rutas para crear archivos adjuntos y publicar la Vista de profesor y iframes de vista de estudiante.
  • Envía las siguientes solicitudes a la API de complementos de Google Classroom:
    • Crea un nuevo archivo adjunto.
    • Obtén el contexto del complemento, que identifica si el usuario que accedió es un como estudiante o profesor.

Cuando termines, puedes crear archivos adjuntos de contenido en las tareas a través de la IU de Google Classroom cuando accedas como profesor. Profesores y estudiantes en la clase también puede ver el contenido.

Habilita la API de Classroom

Realiza llamadas a la API de Classroom a partir de este paso. La API debe estar habilitado para tu proyecto de Google Cloud antes de que puedas llamarlo. Navegación a la entrada de la biblioteca de la API de Google Classroom y elige Habilitar.

Controla los parámetros de consulta de la vista de descubrimiento de archivos adjuntos

Como se explicó anteriormente, Google Classroom pasa los parámetros de consulta cuando Carga de la vista de descubrimiento de archivos adjuntos en el iframe:

  • courseId: Es el ID del curso actual de Classroom.
  • itemId: Es un identificador único para los cursos CourseWork, CourseWorkMaterial o Anuncio que recibe el archivo adjunto del complemento.
  • itemType: "courseWork" o "courseWorkMaterials" o "anuncio".
  • addOnToken: Es un token que se usa para autorizar ciertos Acciones de complementos de Classroom.
  • login_hint: Es el ID de Google del usuario actual.

En esta explicación, se abordan courseId, itemId, itemType y addOnToken. Retenerlos y pasarlos cuando se hagan llamadas a la API de Classroom

Al igual que en el paso de explicación anterior, almacena los valores de los parámetros de consulta que se pasaron en nuestra sesión. Es importante hacerlo cuando la Vista de descubrimiento de adjuntos se abren por primera vez, ya que esta es la única oportunidad para que Classroom pasar estos parámetros de consulta.

Python

Navega a tu archivo del servidor de Flask que proporciona rutas para el adjunto. Discovery View (attachment-discovery-routes.py si sigue nuestros (ejemplo). En la parte superior de la ruta de destino del complemento (/classroom-addon en el ejemplo proporcionado), recupera y almacena el Parámetros de consulta courseId, itemId, itemType y addOnToken.

# Retrieve the itemId, courseId, and addOnToken query parameters.
if flask.request.args.get("itemId"):
    flask.session["itemId"] = flask.request.args.get("itemId")
if flask.request.args.get("itemType"):
    flask.session["itemType"] = flask.request.args.get("itemType")
if flask.request.args.get("courseId"):
    flask.session["courseId"] = flask.request.args.get("courseId")
if flask.request.args.get("addOnToken"):
    flask.session["addOnToken"] = flask.request.args.get("addOnToken")

Escribe estos valores en la sesión solo si están presentes. no son se pasan de nuevo si el usuario vuelve a la vista de descubrimiento de adjuntos más adelante sin cerrar el iframe.

Agregar almacenamiento persistente para archivos adjuntos de tipo de contenido

Necesitas un registro local de todos los adjuntos creados. Esto te permite buscar contenido que el profesor seleccionó con identificadores proporcionados por en Classroom.

Configura un esquema de base de datos para un Attachment. En el ejemplo proporcionado, se presenta archivos adjuntos que muestren una imagen y una leyenda. Un Attachment contiene lo siguiente: siguientes atributos:

  • attachment_id: Es un identificador único para un archivo adjunto. Asignada por Classroom y se devuelve en la respuesta cuando se crea un adjunto.
  • image_filename: Es el nombre de archivo local de la imagen que se mostrará.
  • image_caption: Es la leyenda que se mostrará con la imagen.

Python

Extiende la implementación de SQLite y flask_sqlalchemy de los pasos anteriores.

Navega hasta el archivo en el que definiste la tabla de usuarios (models.py). si estás siguiendo el ejemplo que te proporcionamos). Agrega lo siguiente al final del archivo debajo de la clase User.

class Attachment(db.Model):
    # The attachmentId is the unique identifier for the attachment.
    attachment_id = db.Column(db.String(120), primary_key=True)

    # The image filename to store.
    image_filename = db.Column(db.String(120))

    # The image caption to store.
    image_caption = db.Column(db.String(120))

Importa la nueva clase de adjunto al archivo del servidor con tu adjunto. las rutas de manejo.

Cómo configurar rutas nuevas

Para comenzar este paso de explicación, configura algunas páginas nuevas en nuestra aplicación. Estas le permiten al usuario crear y ver contenido a través de nuestro complemento.

Agregar rutas de creación de adjuntos

Necesitas páginas para que el profesor seleccione el contenido y emitir archivos adjuntos solicitudes. Implementa la ruta /attachment-options para mostrar las opciones de contenido que seleccione el profesor. También necesitas plantillas para la selección de contenido y páginas de confirmación de creación. Los ejemplos que proporcionamos contienen plantillas para ellas y también puede mostrar las solicitudes y respuestas de la API de Classroom.

Ten en cuenta que, de manera alternativa, puedes modificar la vista existente de descubrimiento de archivos adjuntos página de destino para mostrar las opciones de contenido en lugar de crear la nueva /attachment-options página. Te recomendamos que crees una página nueva para los fines de este ejercicio para que conserves el comportamiento de SSO implementado en el segundo paso de explicación, como la revocación de los permisos de la app. Estos deberían demostrar útil a medida que compilas y pruebas tu complemento.

Los profesores pueden seleccionar entre un pequeño grupo de imágenes subtituladas en las ejemplo. Hemos proporcionado cuatro imágenes de puntos de referencia famosos con leyendas derivadas de los nombres de archivo.

Python

En el ejemplo que proporcionamos, se encuentra en el archivo webapp/attachment_routes.py.

@app.route("/attachment-options", methods=["GET", "POST"])
def attachment_options():
    """
    Render the attachment options page from the "attachment-options.html"
    template.

    This page displays a grid of images that the user can select using
    checkboxes.
    """

    # A list of the filenames in the static/images directory.
    image_filenames = os.listdir(os.path.join(app.static_folder, "images"))

    # The image_list_form_builder method creates a form that displays a grid
    # of images, checkboxes, and captions with a Submit button. All images
    # passed in image_filenames will be shown, and the captions will be the
    # title-cased filenames.

    # The form must be built dynamically due to limitations in WTForms. The
    # image_list_form_builder method therefore also returns a list of
    # attribute names in the form, which will be used by the HTML template
    # to properly render the form.
    form, var_names = image_list_form_builder(image_filenames)

    # If the form was submitted, validate the input and create the attachments.
    if form.validate_on_submit():

        # Build a dictionary that maps image filenames to captions.
        # There will be one dictionary entry per selected item in the form.
        filename_caption_pairs = construct_filename_caption_dictionary_list(
            form)

        # Check that the user selected at least one image, then proceed to
        # make requests to the Classroom API.
        if len(filename_caption_pairs) > 0:
            return create_attachments(filename_caption_pairs)
        else:
            return flask.render_template(
                "create-attachment.html",
                message="You didn't select any images.",
                form=form,
                var_names=var_names)

    return flask.render_template(
        "attachment-options.html",
        message=("You've reached the attachment options page. "
                "Select one or more images and click 'Create Attachment'."),
        form=form,
        var_names=var_names,
    )

Esto produce el mensaje "Crear archivos adjuntos" página que se ve de la siguiente manera:

Ejemplo de una vista de selección de contenido de Python

El profesor puede seleccionar varias imágenes. Crea un archivo adjunto para cada imagen que el profesor seleccionó en el método create_attachments.

Generar solicitudes de creación de archivos adjuntos

Ahora que sabes qué contenido quiere adjuntar, enviar solicitudes a la API de Classroom para crear archivos adjuntos en nuestro asignación. Guarda los detalles del adjunto en tu base de datos luego de recibir un de la API de Classroom.

Comienza por obtener una instancia del servicio Classroom:

Python

En el ejemplo que proporcionamos, se encuentra en el archivo webapp/attachment_routes.py.

def create_attachments(filename_caption_pairs):
    """
    Create attachments and show an acknowledgement page.

    Args:
        filename_caption_pairs: A dictionary that maps image filenames to
            captions.
    """
    # Get the Google Classroom service.
    classroom_service = googleapiclient.discovery.build(
        serviceName="classroom",
        version="v1",
        credentials=credentials)

Emite una solicitud de CREATE a courses.courseWork.addOnAttachments. extremo. Para cada imagen seleccionada por el profesor, primero debes crear una Objeto AddOnAttachment:

Python

En el ejemplo proporcionado, esta es una continuación de create_attachments. .

# Create a new attachment for each image that was selected.
attachment_count = 0
for key, value in filename_caption_pairs.items():
    attachment_count += 1

    # Create a dictionary with values for the AddOnAttachment object fields.
    attachment = {
        # Specifies the route for a teacher user.
        "teacherViewUri": {
            "uri":
                flask.url_for(
                    "load_content_attachment", _scheme='https', _external=True),
        },
        # Specifies the route for a student user.
        "studentViewUri": {
            "uri":
                flask.url_for(
                    "load_content_attachment", _scheme='https', _external=True)
        },
        # The title of the attachment.
        "title": f"Attachment {attachment_count}",
    }

Se deben cumplir, al menos, los campos teacherViewUri, studentViewUri y title para cada archivo adjunto. teacherViewUri y studentViewUri representan las URL que se cargan cuando el archivo adjunto abre el archivo adjunto tipo de usuario respectivo.

Envía el objeto AddOnAttachment en el cuerpo de una solicitud a la dirección extremo addOnAttachments. Proporciona courseId, itemId, itemType y Identificadores addOnToken con cada solicitud.

Python

En el ejemplo proporcionado, esta es una continuación de create_attachments. .

# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
    case "announcements":
        parent = classroom_service.courses().announcements()
    case "courseWorkMaterials":
        parent = classroom_service.courses().courseWorkMaterials()
    case _:
        parent = classroom_service.courses().courseWork()

# Issue a request to create the attachment.
resp = parent.addOnAttachments().create(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"],
    addOnToken=flask.session["addOnToken"],
    body=attachment).execute()

Crea una entrada para este adjunto en tu base de datos local de modo que puedas hacerlo más adelante cargar el contenido correcto. Classroom devuelve un valor id único. en la respuesta a la solicitud de creación, así que use esta clave como la clave primaria en nuestra en la base de datos. Además, ten en cuenta que Classroom aprueba el attachmentId. query cuando abras las vistas del profesor y del estudiante:

Python

En el ejemplo proporcionado, esta es una continuación de create_attachments. .

# Store the value by id.
new_attachment = Attachment(
    # The new attachment's unique ID, returned in the CREATE response.
    attachment_id=resp.get("id"),
    image_filename=key,
    image_caption=value)
db.session.add(new_attachment)
db.session.commit()

Considera dirigir al usuario a una página de confirmación en este punto de que creó archivos adjuntos correctamente.

Permitir los archivos adjuntos de tu complemento

Este es un buen momento para agregar las direcciones apropiadas al adjunto permitido. Campo Prefijos de URI en la Configuración de la app del SDK de Google Workspace Marketplace . Tu complemento solo puede crear archivos adjuntos a partir de uno de los prefijos de URI que se indican en esta página. Esta es una medida de seguridad para ayudar a reducir la posibilidad de los ataques de intermediarios.

El enfoque más simple es proporcionar tu dominio de nivel superior en este campo, por https://example.com de ejemplo. https://localhost:<your port number>/ harían lo siguiente si usas tu máquina local como servidor web.

Cómo agregar rutas para las vistas de profesor y de alumno

Hay cuatro iframes en los que se puede cargar un complemento de Google Classroom. Solo creaste rutas que publican el iframe de vista de descubrimiento de archivos adjuntos. hasta ahora. A continuación, agrega rutas para publicar también los iframes de Vista de profesor y de estudiante.

Para mostrar una vista previa del alumno, se requiere el iframe de Vista del profesor. experiencia, pero opcionalmente puede incluir información adicional o edición atributos.

La Vista del alumno es la página que se muestra a cada estudiante cuando lo abre. un archivo adjunto del complemento.

Para los fines de este ejercicio, crea un solo /load-content-attachment. ruta que entrega la Vista de profesor y de Alumno. Usa la API de Classroom para determinar si un usuario es profesor o estudiante cuando la página .

Python

En el ejemplo que proporcionamos, se encuentra en el archivo webapp/attachment_routes.py.

@app.route("/load-content-attachment")
def load_content_attachment():
    """
    Load the attachment for the user's role."""

    # Since this is a landing page for the Teacher and Student View iframes, we
    # need to preserve the incoming query parameters.
    if flask.request.args.get("itemId"):
        flask.session["itemId"] = flask.request.args.get("itemId")
    if flask.request.args.get("itemType"):
        flask.session["itemType"] = flask.request.args.get("itemType")
    if flask.request.args.get("courseId"):
        flask.session["courseId"] = flask.request.args.get("courseId")
    if flask.request.args.get("attachmentId"):
        flask.session["attachmentId"] = flask.request.args.get("attachmentId")

Ten en cuenta que también debes autenticar al usuario en este punto. Tú también debe manejar el parámetro de consulta login_hint aquí y dirigir al usuario a tu flujo de autorización, si es necesario. Consulta los detalles de la guía de acceso que se analizan en explicaciones anteriores para obtener más información sobre este flujo.

Luego, envía una solicitud al extremo getAddOnContext que coincida con el elemento. el tipo de letra.

Python

En el ejemplo proporcionado, esta es una continuación del load_content_attachment.

# Create an instance of the Classroom service.
classroom_service = googleapiclient.discovery.build(
    serviceName="classroom"
    version="v1",
    credentials=credentials)

# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
    case "announcements":
        parent = classroom_service.courses().announcements()
    case "courseWorkMaterials":
        parent = classroom_service.courses().courseWorkMaterials()
    case _:
        parent = classroom_service.courses().courseWork()

addon_context_response = parent.getAddOnContext(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"]).execute()

Este método devuelve información sobre el rol del usuario actual en la clase. Alterar la visión presentada al usuario según su rol. Exactamente uno de los Los campos studentContext o teacherContext se propagan en la respuesta objeto. Examínalos para determinar cómo dirigirte al usuario.

En cualquier caso, usa el valor del parámetro de consulta attachmentId para saber qué adjunto para recuperar de nuestra base de datos. Este parámetro de consulta se proporciona cuando abriendo los URI de la Vista de profesor o de Alumno.

Python

En el ejemplo proporcionado, esta es una continuación del load_content_attachment.

# Determine which view we are in by testing the returned context type.
user_context = "student" if addon_context_response.get(
    "studentContext") else "teacher"

# Look up the attachment in the database.
attachment = Attachment.query.get(flask.session["attachmentId"])

# Set the text for the next page depending on the user's role.
message_str = f"I see that you're a {user_context}! "
message_str += (
    f"I've loaded the attachment with ID {attachment.attachment_id}. "
    if user_context == "teacher" else
    "Please enjoy this image of a famous landmark!")

# Show the content with the customized message text.
return flask.render_template(
    "show-content-attachment.html",
    message=message_str,
    image_filename=attachment.image_filename,
    image_caption=attachment.image_caption,
    responses=response_strings)

Prueba el complemento

Para probar la creación de archivos adjuntos, completa los siguientes pasos:

  • Accede a [Google Classroom] como uno de tus Usuarios de prueba Teacher.
  • Navega a la pestaña Trabajo en clase y crea una nueva Tarea.
  • Haz clic en el botón Complementos debajo del área de texto y, luego, selecciona tu complemento. Se abre el iframe y el complemento carga el URI de configuración de archivo adjunto que especificadas en la página Configuración de la app del SDK de Google Workspace Marketplace.
  • Elige el contenido que quieres adjuntar a la tarea.
  • Cierra el iframe una vez que se completa el flujo de creación del archivo adjunto.

Deberías ver una tarjeta de archivo adjunto en la IU de creación de tareas de Google Google Classroom Haz clic en la tarjeta para abrir el iframe de la Vista de profesores y confirmar la acción. de que aparezca el archivo adjunto correcto. Haz clic en el botón Asignar.

Completa los siguientes pasos para probar la experiencia de los estudiantes:

  • Luego, accede a Classroom como un estudiante de prueba en el mismo como usuario de prueba profesor.
  • Busca la tarea de prueba en la pestaña Trabajo en clase.
  • Expande la tarea y haz clic en la tarjeta adjunta para abrir la vista de alumno. iframe.

Confirma que aparezca el archivo adjunto correcto para el estudiante.

¡Felicitaciones! Ya puedes continuar con el siguiente paso: crear archivos adjuntos de tipo de actividad.