Pièces jointes au type de contenu

Il s'agit du quatrième tutoriel des modules complémentaires Classroom cette série de tutoriels.

Dans ce tutoriel, vous allez interagir avec l'API Google Classroom pour créer et les pièces jointes. Vous fournissez aux utilisateurs des itinéraires leur permettant d'afficher le contenu des pièces jointes. La Les vues diffèrent en fonction du rôle de l'utilisateur dans le cours. Ce tutoriel aborde les points suivants : pièces jointes liées au type de contenu, qui ne nécessitent pas l'envoi d'un devoir par un élève.

Dans ce tutoriel, vous allez effectuer les opérations suivantes:

  • Récupérez et utilisez les paramètres de requête complémentaires suivants: <ph type="x-smartling-placeholder">
      </ph>
    • addOnToken: jeton d'autorisation transmis à la détection de pièces jointes Vue.
    • itemId: identifiant unique de l'élément CourseWork, CourseWorkMaterial ou Annonce qui reçoit la pièce jointe de module complémentaire.
    • itemType : "courseWork", "courseWorkMaterials" ou "annonce".
    • courseId: identifiant unique du cours Google Classroom dans où l'attribution est en cours de création.
    • attachmentId: identifiant unique attribué par Google Classroom à un 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 pour diffuser la vue enseignant iFrames de la vue élève.
  • Envoyez les requêtes suivantes à l'API des modules complémentaires Google Classroom: <ph type="x-smartling-placeholder">
      </ph>
    • Créez une pièce jointe.
    • Obtenir le contexte du module complémentaire, qui détermine si l'utilisateur connecté est d'un élève ou d'un enseignant.

Une fois l'opération terminée, vous pouvez créer des pièces jointes au type de contenu dans les devoirs via l'interface utilisateur de Google Classroom lorsque vous êtes connecté en tant qu'enseignant. Enseignants et élèves en la classe peut aussi en consulter le contenu.

Activer l'API Classroom

Appelez l'API Classroom en commençant par cette étape. L'API doit pour votre projet Google Cloud avant de pouvoir l'appeler. Itinéraire à 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 de pièces jointes

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

  • courseId: ID du cours Classroom actuel.
  • itemId: identifiant unique de l'élément CourseWork, CourseWorkMaterial ou Annonce qui reçoit la pièce jointe de module complémentaire.
  • itemType : "courseWork", "courseWorkMaterials" ou "annonce".
  • addOnToken: jeton permettant d'autoriser certaines Actions complémentaires Classroom.
  • login_hint: ID Google de l'utilisateur actuel.

Ce tutoriel concerne courseId, itemId, itemType et addOnToken. Conservez-les et transmettez-les lorsque vous appelez l'API Classroom.

Comme lors de l'étape précédente, stockez les valeurs des paramètres de requête transmis dans notre session. Il est important que nous le fassions lorsque la vue Découverte des pièces jointes est car c'est la seule occasion pour Classroom de transmettre ces paramètres de requête.

Python

Accédez au fichier serveur Flask qui fournit des routes à la pièce jointe. Vue Discovery (attachment-discovery-routes.py si vous suivez notre l'exemple fourni). en haut de votre itinéraire de destination du module complémentaire. (/classroom-addon dans l'exemple fourni), récupérez et stockez le 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'indiquez ces valeurs dans la session que si elles sont présentes. elles ne le sont pas transmis à nouveau si l'utilisateur revient à la vue de découverte de pièces jointes sans fermer l'iFrame.

Ajouter un espace de stockage persistant pour les pièces jointes liées au type de contenu

Vous avez besoin d'un enregistrement local de toutes les pièces jointes créées. Cela vous permet de rechercher les contenus sélectionnés par l'enseignant à l'aide des identifiants fournis par Classroom.

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

  • attachment_id: identifiant unique d'un rattachement. Attribué par Classroom et est renvoyé dans la réponse lors de la création d'une en 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 flask_sqlalchemy des étapes précédentes.

Accédez au fichier dans lequel vous avez défini votre table "Utilisateur" (models.py). si vous suivez notre exemple). Ajoutez ce qui suit 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 contenant votre pièce jointe. de gestion des routes.

Configurer de nouveaux itinéraires

Commencez ce tutoriel par la configuration de nouvelles pages dans notre application. Ceux-ci permettent à un utilisateur de créer et de consulter 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 du contenu et créer des pièces jointes requêtes. Implémenter la route /attachment-options pour afficher les options de contenu que l'enseignant doit sélectionner. Vous avez également besoin de modèles pour la sélection de contenu et pages de confirmation de création. Les exemples fournis contiennent des modèles pour ces éléments, et peut aussi afficher les requêtes et les réponses API Classroom.

Notez qu'il est possible de modifier la vue "Découverte des pièces jointes" existante page de destination pour afficher les options de contenu au lieu de créer /attachment-options. Nous vous recommandons de créer une nouvelle page cet exercice afin de préserver le comportement SSO mis en œuvre au cours de la deuxième procédure, comme la révocation des autorisations de l'application. Ceux-ci doivent prouver utiles pour créer et tester votre module complémentaire.

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

Python

Dans l'exemple fourni, elle 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,
    )

L'invite "Create Attachments" (Créer des pièces jointes) s'affiche qui se présente comme suit:

Exemple de vue de sélection de contenu Python

L'enseignant peut sélectionner plusieurs images. Créer une pièce jointe pour chaque image sélectionné 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, d'envoyer des demandes à l'API Classroom pour créer des pièces jointes sur notre l'attribution. Stockez les détails des pièces jointes dans votre base de données après avoir reçu une de l'API Classroom.

Commencez par obtenir une instance du service Classroom:

Python

Dans l'exemple fourni, elle 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.
    classroom_service = googleapiclient.discovery.build(
        serviceName="classroom",
        version="v1",
        credentials=credentials)

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

Python

Dans l'exemple fourni, il s'agit de la suite 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}",
    }

Les champs teacherViewUri, studentViewUri et title doivent au moins être fournies pour chaque pièce jointe. teacherViewUri et studentViewUri représentent les URL qui sont chargées lorsque la pièce jointe est ouverte par le le type d'utilisateur concerné.

Envoyez l'objet AddOnAttachment dans le corps d'une requête à l'adresse Point de terminaison addOnAttachments. Fournissez les éléments courseId, itemId, itemType et Identifiants addOnToken avec chaque requête.

Python

Dans l'exemple fourni, il s'agit de la suite 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()

Créez une entrée pour cette pièce jointe dans votre base de données locale afin de pouvoir la réutiliser ultérieurement charger 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 notre base de données. Notez également que Classroom obtient l'attachmentId lors de l'ouverture des vues "Enseignant" et "Élève" :

Python

Dans l'exemple fourni, il s'agit de la suite 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()

À ce stade, envisagez de rediriger l'utilisateur vers une page de confirmation, qu'ils ont réussi à créer des pièces jointes.

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

C'est le bon moment d'ajouter les adresses appropriées à la pièce jointe autorisée Champ "Préfixes d'URI" dans la section Configuration de l'application du SDK Google Workspace Marketplace . 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. Cette mesure de sécurité vise à réduire le risque des attaques man-in-the-middle.

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

Ajouter des itinéraires pour les vues des enseignants et des élèves

Il existe quatre iFrames dans lesquels un module complémentaire Google Classroom peut être chargé. Vous n'avez créé que des routes qui diffusent l'iFrame de la vue de découverte des pièces jointes. à distance. Ensuite, ajoutez des itinéraires pour diffuser également les iFrames "Teachers" et "Student View".

L'iFrame Vue enseignant est nécessaire pour afficher un aperçu de l'élève mais il peut aussi inclure des informations supplémentaires ou des modifications caractéristiques.

La vue Élève est la page qui est présentée à chaque élève lorsqu'il ouvre la page. une pièce jointe de module complémentaire.

Pour les besoins de cet exercice, créez un seul élément /load-content-attachment. qui dessert à la fois la vue des enseignants et celle des élèves. Utiliser l'API Classroom pour déterminer si l'utilisateur est un enseignant ou un élève lorsque la page charge.

Python

Dans l'exemple fourni, elle 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. Toi doit également gérer le paramètre de requête login_hint ici et rediriger l'utilisateur vers votre flux d'autorisation si nécessaire. Reportez-vous aux instructions relatives à la connexion présentées dans les tutoriels précédents pour en savoir plus sur ce flux.

Envoyez ensuite une requête au point de terminaison getAddOnContext correspondant à l'élément de mots clés.

Python

Dans l'exemple que nous avons fourni, ceci fait suite à la 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()

Cette méthode renvoie des informations sur le rôle de l'utilisateur actuel dans la classe. Modifiez l'affichage présenté à l'utilisateur en fonction de son rôle. Une des Les champs studentContext ou teacherContext sont renseignés dans la réponse objet. 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 à récupérer dans notre base de données. Ce paramètre de requête est fourni lorsque en ouvrant les URI de l'enseignant ou de la vue élève.

Python

Dans l'exemple que nous avons fourni, ceci fait suite à la 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 des pièces jointes, procédez comme suit:

  • Connectez-vous à [Google Classroom] en tant que Enseignants utilisateurs 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 spécifiés sur la page Configuration de l'application du SDK Google Workspace Marketplace.
  • Choisissez le contenu à joindre au devoir.
  • Fermez l'iFrame une fois le processus de création de pièces jointes terminé.

Vous devriez voir apparaître une fiche de pièce jointe dans l'interface utilisateur de création d'un devoir dans Google. Google Classroom. Cliquez sur la fiche pour ouvrir l'iFrame "Vue enseignant" et confirmez. que la pièce jointe appropriée s'affiche. 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 en tant qu'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 la vue Élèves. iFrame.

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

Félicitations ! Vous pouvez passer à l'étape suivante: créer les pièces jointes liées au type d'activité.