Pièces jointes au type de contenu

Il s'agit du quatrième tutoriel de la série de tutoriels sur les modules complémentaires Classroom.

Dans ce tutoriel, vous interagissez avec l'API Google Classroom pour créer des pièces jointes. Vous indiquez des routes aux utilisateurs pour qu'ils puissent afficher le contenu des pièces jointes. Les vues diffèrent selon le rôle de l'utilisateur dans la classe. Ce tutoriel porte sur les pièces jointes de type de contenu, pour lesquelles il n'est pas nécessaire de soumettre un élève.

Au cours de ce tutoriel, vous allez effectuer les opérations suivantes:

  • Récupérez et utilisez les paramètres de requête de module complémentaire suivants :
    • addOnToken: jeton d'autorisation transmis à la vue de découverte des pièces jointes.
    • itemId: identifiant unique du CourseWork, du CourseWorkMaterial ou de l'annonce qui reçoit la pièce jointe du module complémentaire.
    • itemType : "courseWork", "courseWorkMaterials" ou "announcement".
    • courseId: identifiant unique du cours Google Classroom dans lequel le devoir est en cours de création.
    • attachmentId: identifiant unique attribué par Google Classroom à une pièce jointe de module complémentaire après sa création.
  • Implémentez un stockage persistant pour les pièces jointes de type contenu.
  • Fournissez des itinéraires pour créer des pièces jointes et diffuser les iFrames des vues des enseignants et des élèves.
  • Envoyez les requêtes suivantes à l'API des modules complémentaires Google Classroom :
    • Créez une pièce jointe.
    • Obtenez le contexte du module complémentaire, qui détermine si l'utilisateur connecté est un élève ou un enseignant.

Une fois que vous avez terminé, vous pouvez créer des pièces jointes de type de contenu pour les devoirs via l'interface utilisateur de Google Classroom lorsque vous êtes connecté en tant qu'enseignant. Les enseignants et les élèves de la classe peuvent également en consulter le contenu.

Activer l'API Classroom

Appelez l'API Classroom en commençant par cette étape. Pour que vous puissiez appeler l'API, celle-ci doit être activée pour votre projet Google Cloud. Accédez à l'entrée de la bibliothèque de l'API Google Classroom et sélectionnez Activer.

Gérer les paramètres de requête de la vue de découverte des pièces jointes

Comme indiqué précédemment, Google Classroom transmet les paramètres de requête lors du chargement de la vue de découverte des pièces jointes dans l'iFrame:

  • courseId: ID du cours Classroom actuel.
  • itemId: identifiant unique du CourseWork, du CourseWorkMaterial ou de l'annonce qui reçoit la pièce jointe du module complémentaire.
  • itemType : "courseWork", "courseWorkMaterials" ou "announcement".
  • addOnToken: jeton utilisé pour autoriser certaines actions du module complémentaire Classroom.
  • login_hint: ID Google de l'utilisateur actuel.
  • hd: domaine de l'hôte de l'utilisateur actuel, tel que example.com.

Ce tutoriel concerne courseId, itemId, itemType et addOnToken. Conservez et transmettez-les lors de l'émission d'appels vers l'API Classroom.

Comme à l'étape précédente, stockez les valeurs des paramètres de requête transmises dans notre session. Il est important de le faire lors de la première ouverture de la vue de découverte des pièces jointes, car il s'agit de la seule opportunité pour Classroom de transmettre ces paramètres de requête.

Python

Accédez au fichier de serveur Flask qui fournit des routes pour la vue de découverte des pièces jointes (attachment-discovery-routes.py si vous suivez l'exemple fourni). En haut de l'itinéraire de destination de votre module complémentaire (/classroom-addon dans notre exemple fourni), récupérez et stockez les paramètres de requête courseId, itemId, itemType et 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")

N'écrivez ces valeurs dans la session que si elles sont présentes. Elles ne sont pas transmises à nouveau si l'utilisateur revient plus tard à la vue de découverte des pièces jointes sans fermer l'iFrame.

Ajouter un espace de stockage persistant pour les pièces jointes de type contenu

Vous devez conserver un enregistrement local de toutes les pièces jointes créées. Cela vous permet de rechercher le contenu sélectionné par l'enseignant à l'aide des identifiants fournis par Classroom.

Configurez un schéma de base de données pour un élément Attachment. L'exemple fourni présente des pièces jointes affichant une image et une légende. Un Attachment contient les attributs suivants:

  • attachment_id: identifiant unique d'une pièce jointe. Attribué par Classroom et renvoyé dans la réponse lors de la création d'une pièce jointe.
  • image_filename: nom de fichier local de l'image à afficher.
  • image_caption: légende à afficher avec l'image.

Python

Étendez l'implémentation de SQLite et de flask_sqlalchemy à partir des étapes précédentes.

Accédez au fichier dans lequel vous avez défini la table "User" (models.py si vous suivez l'exemple fourni). Ajoutez les éléments suivants en bas du fichier sous la classe 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))

Importez la nouvelle classe Attachment dans le fichier serveur avec vos routes de gestion des pièces jointes.

Configurer de nouvelles routes

Commencez cette étape du tutoriel en configurant de nouvelles pages dans votre application. Elles permettent aux utilisateurs de créer et d'afficher du contenu via notre module complémentaire.

Ajouter des routes de création de pièces jointes

Vous avez besoin de pages pour que l'enseignant puisse sélectionner le contenu et envoyer des demandes de création de pièces jointes. Implémentez la route /attachment-options pour afficher les options de contenu que l'enseignant peut sélectionner. Vous avez également besoin de modèles pour les pages de sélection de contenu et de confirmation de création. Les exemples fournis contiennent des modèles pour ces éléments. Ils peuvent également afficher les requêtes et les réponses de l'API Classroom.

Notez que vous pouvez également modifier votre page de destination existante de vue de découverte des pièces jointes pour afficher les options de contenu au lieu de créer la page /attachment-options. Nous vous recommandons de créer une nouvelle page pour les besoins de cet exercice afin de conserver le comportement SSO implémenté dans la deuxième étape de la procédure, telle que la révocation des autorisations de l'application. Celles-ci devraient s'avérer utiles lorsque vous créez et testez votre module complémentaire.

Un enseignant peut choisir parmi un petit ensemble d'images avec légende dans l'exemple fourni. Nous avons fourni quatre images de monuments célèbres dont les légendes sont dérivées des noms de fichiers.

Python

Dans l'exemple fourni, il se trouve dans le fichier 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,
    )

La page "Créer des pièces jointes" qui s'affiche se présente comme suit:

Exemple de vue de sélection de contenu Python

L'enseignant peut sélectionner plusieurs images. Créez une pièce jointe pour chaque image sélectionnée par l'enseignant dans la méthode create_attachments.

Envoyer des demandes de création de pièces jointes

Maintenant que vous savez quels contenus l'enseignant souhaite joindre, envoyez des demandes à l'API Classroom pour ajouter des pièces jointes à notre devoir. Stockez les détails de la pièce jointe dans votre base de données après avoir reçu une réponse de l'API Classroom.

Commencez par obtenir une instance du service Classroom:

Python

Dans l'exemple fourni, il se trouve dans le fichier 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.
    # We need to request the Classroom API from a specific URL while add-ons
    # are in Early Access.

    # A Google API Key can be created in your Google Cloud project's Credentials
    # settings: https://console.cloud.google.com/apis/credentials.
    # Click "Create Credentials" at top and choose "API key", then provide
    # the key in the discoveryServiceUrl below.
    classroom_service = googleapiclient.discovery.build(
        serviceName="classroom",
        version="v1",
        discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=ADD_ONS_ALPHA&key={GOOGLE_API_KEY}",
        credentials=credentials)

Envoyez une requête CREATE au point de terminaison courses.courseWork.addOnAttachments. Pour chaque image sélectionnée par l'enseignant, créez d'abord un objet AddOnAttachment:

Python

Dans l'exemple fourni, il s'agit d'une continuation de la méthode 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}",
    }

Vous devez fournir au moins les champs teacherViewUri, studentViewUri et title pour chaque rattachement. teacherViewUri et studentViewUri représentent les URL chargées lorsque la pièce jointe est ouverte par le type d'utilisateur concerné.

Envoyez l'objet AddOnAttachment dans le corps d'une requête au point de terminaison addOnAttachments approprié. Fournissez les identifiants courseId, itemId, itemType et addOnToken avec chaque requête.

Python

Dans l'exemple fourni, il s'agit d'une continuation de la méthode 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()

Créez une entrée pour ce rattachement dans votre base de données locale afin de pouvoir charger ultérieurement le contenu approprié. Classroom renvoie une valeur id unique dans la réponse à la requête de création. Vous devez donc l'utiliser comme clé primaire dans votre base de données. Notez également que Classroom transmet le paramètre de requête attachmentId lors de l'ouverture des vues "Enseignant" et "Élève" :

Python

Dans l'exemple fourni, il s'agit d'une continuation de la méthode 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()

Envisagez de rediriger l'utilisateur vers une page de confirmation à ce stade et confirmez qu'il a bien créé les rattachements.

Autoriser les pièces jointes de votre module complémentaire

C'est le bon moment pour ajouter toutes les adresses appropriées dans le champ "Préfixes d'URI autorisés pour les pièces jointes" sur la page de configuration de l'application du SDK GWM. Votre module complémentaire ne peut créer des pièces jointes qu'à partir de l'un des préfixes d'URI répertoriés sur cette page. Il s'agit d'une mesure de sécurité visant à réduire le risque d'attaques MITM ("man in the middle").

L'approche la plus simple consiste à indiquer votre domaine de premier niveau dans ce champ, par exemple https://example.com. https://localhost:<your port number>/ fonctionne si vous utilisez votre ordinateur local en tant que serveur Web.

Ajouter des itinéraires pour les vues "Enseignant" et "Élève"

Un module complémentaire Google Classroom peut être chargé au sein de quatre iFrames. Jusqu'à présent, vous n'avez créé que des routes qui diffusent l'iFrame de la vue de découverte des pièces jointes. Ajoutez ensuite des itinéraires afin de diffuser également les iFrames des vues des enseignants et des élèves.

L'iFrame Teacher View est nécessaire pour afficher un aperçu de l'expérience des élèves, mais peut éventuellement inclure des informations ou des fonctionnalités de modification supplémentaires.

La vue des élèves est la page qui s'affiche lorsque chaque élève ouvre la pièce jointe d'un module complémentaire.

Pour les besoins de cet exercice, créez une route /load-content-attachment unique qui dessert à la fois la vue "Enseignant" et la vue "Élève". Utilisez les méthodes de l'API Classroom pour déterminer si l'utilisateur est un enseignant ou un élève lors du chargement de la page.

Python

Dans l'exemple fourni, il se trouve dans le fichier 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")

N'oubliez pas que vous devez également authentifier l'utilisateur à ce stade. Vous devez également gérer ici les paramètres de requête login_hint et hd, et acheminer l'utilisateur vers votre flux d'autorisation si nécessaire. Pour en savoir plus sur ce flux, consultez les conseils de connexion décrits dans les tutoriels précédents.

Envoyez ensuite une requête au point de terminaison getAddOnContext correspondant au type d'élément.

Python

Dans l'exemple fourni, il s'agit d'une continuation de la méthode load_content_attachment.

# Create an instance of the Classroom service.
classroom_service = googleapiclient.discovery.build(
    serviceName="classroom"
    version="v1",
    discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=ADD_ONS_ALPHA&key={GOOGLE_API_KEY}",
    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()

Cette méthode renvoie des informations sur le rôle de l'utilisateur actuel dans la classe. Modifier la vue présentée à l'utilisateur en fonction de son rôle. Un seul des champs studentContext ou teacherContext est renseigné dans l'objet de réponse. Examinez-les pour déterminer comment vous adresser à l'utilisateur.

Dans tous les cas, utilisez la valeur du paramètre de requête attachmentId pour savoir quelle pièce jointe récupérer dans notre base de données. Ce paramètre de requête est fourni lors de l'ouverture de l'URI de la vue "Enseignant" ou "Élève".

Python

Dans l'exemple fourni, il s'agit d'une continuation de la méthode 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)

Tester le module complémentaire

Pour tester la création d'une pièce jointe:

  • Connectez-vous à [Google Classroom] en tant que enseignant en tant qu'utilisateur test.
  • Accédez à l'onglet Travaux et devoirs et créez un devoir.
  • Cliquez sur le bouton Modules complémentaires sous la zone de texte, puis sélectionnez votre module complémentaire. L'iFrame s'ouvre et le module complémentaire charge l'URI de configuration des pièces jointes que vous avez spécifié sur la page Configuration de l'application du SDK GWM.
  • Choisissez un contenu à joindre au devoir.
  • Fermez l'iFrame une fois le processus de création de la pièce jointe terminé.

Une fiche de pièce jointe devrait s'afficher dans l'interface utilisateur de création des devoirs de Google Classroom. Cliquez sur la fiche pour ouvrir l'iFrame de la vue enseignant, puis vérifiez que la bonne pièce jointe apparaît. Cliquez sur le bouton Attribuer.

Pour tester l'expérience des élèves, procédez comme suit:

  • Connectez-vous ensuite à Classroom en tant qu'utilisateur test élève de la même classe que l'utilisateur test enseignant.
  • Recherchez le devoir test dans l'onglet "Travaux et devoirs".
  • Développez le devoir et cliquez sur la fiche de la pièce jointe pour ouvrir l'iFrame de la vue des élèves.

Vérifiez que la bonne pièce jointe s'affiche pour l'élève.

Félicitations ! Vous êtes prêt à passer à l'étape suivante: la création de rattachements de type activité.