Inhaltstyp-Anhänge

Dies ist die vierte Schritt-für-Schritt-Anleitung für Classroom-Add-ons.

In dieser Schritt-für-Schritt-Anleitung interagieren Sie mit der Google Classroom API, um Anhänge zu erstellen. Sie geben Nutzern die Möglichkeit, sich den Inhalt des Anhangs anzusehen. Die Ansichten unterscheiden sich je nach Rolle des Nutzers in der Klasse. In dieser Schritt-für-Schritt-Anleitung werden Anhänge von Inhaltstypen behandelt, für die keine Einreichung von Schülern/Studenten erforderlich ist.

Im Verlauf dieser Schritt-für-Schritt-Anleitung führen Sie folgende Schritte aus:

  • Rufen Sie die folgenden Add-on-Abfrageparameter ab und verwenden Sie sie:
    • addOnToken: Ein Autorisierungstoken, das an die Ansicht zum Ermitteln von Anhängen übergeben wird.
    • itemId: Eine eindeutige Kennung für das Training, das KursWorkMaterial oder die Ankündigung, die den Add-on-Anhang erhält.
    • itemType: entweder „courseWork“, „courseWorkMaterials“ oder „announcement“.
    • courseId: Eine eindeutige Kennung für den Google Classroom-Kurs, in dem die Aufgabe erstellt wird.
    • attachmentId: Eine eindeutige Kennung, die einem Add-on-Anhang nach dem Erstellen von Google Classroom zugewiesen wird.
  • Implementieren Sie dauerhaften Speicher für Inhaltstyp-Anhänge.
  • Geben Sie Routen an, um Anhänge zu erstellen und die iFrames in der Ansicht „Lehrkraft“ und „Schüler-/Studentenansicht“ bereitzustellen.
  • Senden Sie die folgenden Anfragen an die Google Classroom Add-ons API:
    • Erstellen Sie einen neuen Anhang.
    • Mit dem Add-on-Kontext wird ermittelt, ob der angemeldete Nutzer ein Schüler/Student oder eine Lehrkraft ist.

Wenn Sie fertig sind, können Sie über die Google Classroom-Benutzeroberfläche, wenn Sie als Lehrkraft angemeldet sind, Inhaltstyp-Anhänge zu Aufgaben erstellen. Lehrkräfte und Schüler/Studenten können sich die Inhalte ebenfalls ansehen.

Classroom API aktivieren

Rufen Sie die Classroom API auf, beginnend mit diesem Schritt. Die API muss für Ihr Google Cloud-Projekt aktiviert werden, bevor Sie Aufrufe an sie senden können. Gehen Sie zum Bibliothekseintrag der Google Classroom API und wählen Sie Aktivieren aus.

Abfrageparameter für die Ansicht zur Anhangssuche verarbeiten

Wie bereits erläutert, übergibt Google Classroom Abfrageparameter beim Laden der Ansicht zur Anhangserkennung im iFrame:

  • courseId: Die ID des aktuellen Classroom-Kurses.
  • itemId: Eine eindeutige Kennung für das Training, das KursWorkMaterial oder die Ankündigung, die den Add-on-Anhang erhält.
  • itemType: entweder „courseWork“, „courseWorkMaterials“ oder „announcement“.
  • addOnToken: Ein Token, mit dem bestimmte Aktionen von Classroom-Add-ons autorisiert werden.
  • login_hint: Die Google-ID des aktuellen Nutzers.

Diese Schritt-für-Schritt-Anleitung richtet sich an courseId, itemId, itemType und addOnToken. Sie können sie aufbewahren und übergeben, wenn Sie Aufrufe an die Classroom API senden.

Speichern Sie wie im vorherigen Schritt-für-Schritt-Schritt die übergebenen Abfrageparameterwerte in unserer Sitzung. Es ist wichtig, dass wir das tun, wenn die Ansicht zur Anhangserkennung zum ersten Mal geöffnet wird, da Classroom die einzige Möglichkeit ist, diese Abfrageparameter zu übergeben.

Python

Rufen Sie Ihre Flask-Serverdatei auf, die Routen für die Ansicht zur Anhangserkennung bereitstellt (attachment-discovery-routes.py, wenn Sie unserem Beispiel folgen). Rufen Sie oben in Ihrer Add-on-Landingpage (in unserem Beispiel /classroom-addon) die Abfrageparameter courseId, itemId, itemType und addOnToken ab und speichern Sie sie.

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

Schreiben Sie diese Werte nur in die Sitzung, wenn sie vorhanden sind. Sie werden nicht noch einmal übergeben, wenn der Nutzer später zur Ansicht zur Anhangerkennung zurückkehrt, ohne den iFrame zu schließen.

Dauerhaften Speicher für Inhaltstyp-Anhänge hinzufügen

Sie benötigen einen lokalen Datensatz für alle erstellten Anhänge. So können Sie anhand der von Classroom bereitgestellten Kennungen nach Inhalten suchen, die die Lehrkraft ausgewählt hat.

Richten Sie ein Datenbankschema für ein Attachment ein. Unser Beispiel zeigt Anhänge mit einem Bild und einer Bildunterschrift. Ein Attachment enthält die folgenden Attribute:

  • attachment_id: Eine eindeutige Kennung für einen Anhang. Von Classroom zugewiesen und in der Antwort beim Erstellen eines Anhangs zurückgegeben.
  • image_filename: Der lokale Dateiname des Bildes, das angezeigt werden soll.
  • image_caption: Der Untertitel, der mit dem Bild angezeigt werden soll.

Python

Erweitern Sie die SQLite- und flask_sqlalchemy-Implementierung aus den vorherigen Schritten.

Rufen Sie die Datei auf, in der Sie Ihre Nutzertabelle definiert haben (models.py, wenn Sie unserem Beispiel folgen). Fügen Sie am Ende der Datei unter der Klasse User Folgendes ein:

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

Importieren Sie die neue Anhangsklasse in die Serverdatei mit Ihrem Anhang, der Routen verarbeitet.

Neue Routen einrichten

Beginnen Sie diesen Schritt, indem Sie einige neue Seiten in unserer Anwendung einrichten. Damit können Nutzer Inhalte über unser Add-on erstellen und ansehen.

Routen zur Anhangerstellung hinzufügen

Sie benötigen Seiten, auf denen die Lehrkraft Inhalte auswählen und Anfragen zum Erstellen von Anhängen ausstellen kann. Implementieren Sie die Route /attachment-options, um Inhaltsoptionen aufzurufen, die die Lehrkraft auswählen kann. Außerdem benötigen Sie Vorlagen für die Bestätigungsseiten zur Auswahl und Erstellung von Inhalten. Unsere bereitgestellten Beispiele enthalten Vorlagen dafür. Außerdem können darin die Anfragen und Antworten der Classroom API angezeigt werden.

Sie können alternativ die vorhandene Landingpage der Ansicht für die Anhangserkennung so ändern, dass die Inhaltsoptionen angezeigt werden, anstatt die neue /attachment-options-Seite zu erstellen. Wir empfehlen, für diese Übung eine neue Seite zu erstellen, damit das im zweiten Schritt der Schritt-für-Schritt-Anleitung implementierte SSO-Verhalten wie das Widerrufen der App-Berechtigungen beibehalten wird. Diese sollten sich beim Erstellen und Testen Ihres Add-ons als nützlich erweisen.

Eine Lehrkraft kann in unserem Beispiel aus einer kleinen Gruppe von Bildern mit Untertiteln auswählen. Wir haben vier Bilder berühmter Sehenswürdigkeiten bereitgestellt, deren Untertitel aus den Dateinamen abgeleitet wurden.

Python

In unserem Beispiel befindet sich dies in der Datei 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,
    )

Dadurch wird die Seite "Anhänge erstellen" erstellt, die in etwa so aussieht:

Ansicht für die Auswahl von Beispielinhalten für Python

Die Lehrkraft kann mehrere Bilder auswählen. Erstellen Sie einen Anhang für jedes Bild, das die Lehrkraft in der Methode create_attachments ausgewählt hat.

Anfragen zum Erstellen von Anhängen senden

Nachdem Sie nun wissen, welche Inhalte die Lehrkraft anhängen möchte, können Sie Anfragen an die Classroom API senden, um Anhänge zu unserer Aufgabe zu erstellen. Speichern Sie die Details des Anhangs in Ihrer Datenbank, nachdem Sie eine Antwort von der Classroom API erhalten haben.

Rufen Sie zuerst eine Instanz des Classroom-Dienstes ab:

Python

In unserem Beispiel befindet sich dies in der Datei 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)

Senden Sie eine CREATE-Anfrage an den Endpunkt courses.courseWork.addOnAttachments. Erstellen Sie für jedes von der Lehrkraft ausgewählte Bild zuerst ein AddOnAttachment-Objekt:

Python

In unserem Beispiel ist dies eine Fortsetzung der Methode 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}",
    }

Für jeden Anhang müssen mindestens die Felder teacherViewUri, studentViewUri und title angegeben werden. teacherViewUri und studentViewUri stellen die URLs dar, die geladen werden, wenn der Anhang durch den jeweiligen Nutzertyp geöffnet wird.

Senden Sie das Objekt AddOnAttachment im Text einer Anfrage an den entsprechenden addOnAttachments-Endpunkt. Geben Sie bei jeder Anfrage die IDs courseId, itemId, itemType und addOnToken an.

Python

In unserem Beispiel ist dies eine Fortsetzung der Methode 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()

Erstellen Sie einen Eintrag für diesen Anhang in Ihrer lokalen Datenbank, damit Sie später den richtigen Inhalt laden können. Classroom gibt in der Antwort auf die Erstellungsanfrage einen eindeutigen id-Wert zurück. Verwenden Sie diesen daher als Primärschlüssel in unserer Datenbank. Beachten Sie außerdem, dass Classroom beim Öffnen der Ansicht für Lehrkräfte und Schüler/Studenten den Abfrageparameter attachmentId übergibt:

Python

In unserem Beispiel ist dies eine Fortsetzung der Methode 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()

Erwägen Sie, den Nutzer an dieser Stelle auf eine Bestätigungsseite weiterzuleiten und zu bestätigen, dass er Anhänge erstellt hat.

Anhänge aus Ihrem Add-on zulassen

Jetzt ist ein guter Zeitpunkt, im Google Workspace Marketplace SDK auf der Seite App-Konfiguration im Feld „Zulässige URI-Präfixe für Anhänge“ die entsprechenden Adressen hinzuzufügen. Das Add-on kann Anhänge nur mit einem der auf dieser Seite aufgeführten URI-Präfixe erstellen. Dies ist eine Sicherheitsmaßnahme, die dazu beitragen soll, das Risiko von Man-in-the-Middle-Angriffen zu verringern.

Die einfachste Methode besteht darin, die Top-Level-Domain in diesem Feld anzugeben, z. B. https://example.com. https://localhost:<your port number>/ funktioniert, wenn Sie Ihren lokalen Computer als Webserver verwenden.

Routen für die Ansicht für Lehrkräfte und Schüler/Studenten hinzufügen

Es gibt vier iFrames, in denen ein Google Classroom-Add-on geladen werden kann. Sie haben nur Routen erstellt, die den iFrame der Anhangserkennungsansicht weithin bereitstellen. Fügen Sie als Nächstes Routen hinzu, die auch den iFrames in der Ansicht für Lehrkräfte und Schüler/Studenten angezeigt werden sollen.

Der iFrame Teacher View ist erforderlich, um eine Vorschau der Aktivitäten für Schüler und Studenten anzuzeigen. Optional kann er aber zusätzliche Informationen oder Bearbeitungsfunktionen enthalten.

Die Schüleransicht ist die Seite, die jedem Schüler angezeigt wird, wenn er einen Add-on-Anhang öffnet.

Erstellen Sie für diese Übung eine einzelne /load-content-attachment-Route für die Ansicht für Lehrkräfte und für Schüler und Studenten. Verwenden Sie Classroom API-Methoden, um festzustellen, ob der Nutzer eine Lehrkraft oder ein Schüler oder Student ist, wenn die Seite geladen wird.

Python

In unserem Beispiel befindet sich dies in der Datei 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")

Vergessen Sie nicht, dass Sie den Nutzer an diesem Punkt auch authentifizieren sollten. Du solltest hier auch den Abfrageparameter login_hint verarbeiten und den Nutzer gegebenenfalls zu deinem Autorisierungsvorgang weiterleiten. Weitere Informationen zu diesem Vorgang finden Sie in den Details zur Anleitung bei der Anmeldung, die in den vorherigen Schritt-für-Schritt-Anleitungen erläutert wurden.

Senden Sie dann eine Anfrage an den Endpunkt getAddOnContext, die dem Elementtyp entspricht.

Python

In unserem Beispiel ist dies eine Fortsetzung der Methode 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()

Diese Methode gibt Informationen zur Rolle des aktuellen Nutzers in der Klasse zurück. Die für den Nutzer angezeigte Ansicht je nach Rolle ändern. Im Antwortobjekt ist genau eines der Felder studentContext oder teacherContext ausgefüllt. Untersuchen Sie diese, um zu ermitteln, wie Sie die Nutzenden ansprechen können.

In jedem Fall sollten Sie den Wert des Abfrageparameters attachmentId verwenden, um zu wissen, welcher Anhang aus der Datenbank abgerufen werden soll. Dieser Abfrageparameter wird bereitgestellt, wenn der URI für die Lehrkräfte- oder Schüleransicht geöffnet wird.

Python

In unserem Beispiel ist dies eine Fortsetzung der Methode 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)

Add-on testen

Führen Sie die folgenden Schritte aus, um das Erstellen von Anhängen zu testen:

  • Melden Sie sich in [Google Classroom] als einer Ihrer Teacher-Testnutzer an.
  • Gehen Sie zum Tab Kursaufgaben und erstellen Sie eine neue Aufgabe.
  • Klicken Sie unter dem Textbereich auf die Schaltfläche Add-ons und wählen Sie das gewünschte Add-on aus. Der iFrame wird geöffnet und das Add-on lädt den Einrichtungs-URI für den Anhang, den Sie auf der Seite App-Konfiguration des Google Workspace Marketplace SDK angegeben haben.
  • Wählen Sie einen Inhalt aus, der an die Aufgabe angehängt werden soll.
  • Schließen Sie den iFrame, nachdem der Anhang erstellt wurde.

Auf der Benutzeroberfläche zum Erstellen von Aufgaben in Google Classroom sollte nun eine Karte mit Anhängen angezeigt werden. Klicken Sie auf die Karte, um den iFrame der Lehrkraft-Ansicht zu öffnen, und prüfen Sie, ob der richtige Anhang angezeigt wird. Klicken Sie auf die Schaltfläche Zuweisen.

So testen Sie die Funktionen für Schüler/Studenten:

  • Melden Sie sich dann in Classroom als Schüler-/Studententestnutzer in demselben Kurs an wie der Lehrer-Testnutzer.
  • Suchen Sie auf dem Tab „Kursaufgaben“ nach der Testaufgabe.
  • Maximieren Sie die Aufgabe und klicken Sie auf die Karte des Anhangs, um den iFrame für die Schüler-/Studentenansicht zu öffnen.

Prüfen Sie, ob der richtige Anhang für den Schüler/Studenten angezeigt wird.

Glückwunsch! Sie können nun mit dem nächsten Schritt fortfahren: Anhänge vom Typ „Aktivität“ erstellen.