Załączniki typu treści

To czwarta prezentacja z serii omówienia dodatków do Classroom.

W tym samouczku dowiesz się, jak tworzyć załączniki za pomocą interfejsu Google Classroom API. Użytkownicy mogą wyświetlać treści załącznika na różne sposoby. Widoki różnią się w zależności od roli użytkownika w zajęciach. Ten przewodnik dotyczy załączników typu „treści”, które nie wymagają przesyłania przez uczniów.

W trakcie tego samouczka wykonasz te czynności:

  • Pobieraj i używaj tych parametrów zapytania dotyczących dodatku:
    • addOnToken: token autoryzacji przekazany do widoku wykrywania załączników.
    • itemId: unikalny identyfikator zajęć, materiału dydaktycznego lub ogłoszenia, któremu przypisujesz załącznik dodatku.
    • itemType: „courseWork”, „courseWorkMaterials” lub „announcement”.
    • courseId: unikalny identyfikator kursu Google Classroom, w którym tworzony jest projekt.
    • attachmentId: unikalny identyfikator przypisany przez Google Classroom do załącznika dodatku po jego utworzeniu.
  • Wdrożyć trwałe miejsce na dane dla załączników typu content.
  • Podaj ścieżki do tworzenia załączników oraz wyświetlania ramek iframe widoku nauczyciela i widoku ucznia.
  • Wyślij te żądania do interfejsu Add-ons API Google Classroom:
    • Utwórz nowy załącznik.
    • Pobierz kontekst dodatku, który określa, czy zalogowany użytkownik jest uczniem czy nauczycielem.

Po zakończeniu możesz utworzyć załączniki typu treści w projektach za pomocą interfejsu Google Classroom po zalogowaniu się jako nauczyciel. Treści mogą wyświetlać również nauczyciele i uczniowie na zajęciach.

Włączanie interfejsu Classroom API

Zacznij od tego kroku, aby wykonywać wywołania interfejsu Classroom API. Zanim będzie można wywoływać interfejs API, musisz go włączyć w projekcie Google Cloud. Przejdź do interfejsu Google Classroom API i wybierz Włącz.

Obsługa parametrów zapytania widoku danych pliku załącznika

Jak już wspomnieliśmy, Google Classroom przekazuje parametry zapytań podczas wczytywania widoku karty informacji o załączniku w elemencie iframe:

  • courseId: identyfikator bieżącego kursu w Classroom.
  • itemId: unikalny identyfikator zajęć, materiału dydaktycznego lub ogłoszenia, któremu przypisujesz załącznik dodatku.
  • itemType: „courseWork”, „courseWorkMaterials” lub „announcement”.
  • addOnToken: token używany do autoryzacji niektórych działań dodatku Classroom.
  • login_hint: identyfikator Google bieżącego użytkownika.

Ten przewodnik dotyczy courseId, itemId, itemTypeaddOnToken. Zachowaj te wartości i przekazuj je podczas wywoływania interfejsu Classroom API.

Podobnie jak w poprzednim kroku, zapisz w sesji wartości przekazanych parametrów zapytania. Ważne jest, abyśmy to zrobili, gdy po raz pierwszy otworzymy widok wyszukiwania załączników, ponieważ jest to jedyna okazja dla Classroom do przekazania tych parametrów zapytania.

Python

Otwórz plik serwera Flask, który zawiera trasy dla widoku widoku Attachment Discovery (attachment-discovery-routes.py, jeśli korzystasz z naszego przykładu). U góry ścieżki docelowej dodatku (/classroom-addon w naszym przykładzie) pobierz i zapisz parametry zapytania courseId, itemId, itemTypeaddOnToken.

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

Zapisz te wartości w sesji tylko wtedy, gdy są one obecne. Nie są one przekazywane ponownie, jeśli użytkownik wróci do widoku wykrywania załączników bez zamykania ramki iframe.

Dodawanie stałego miejsca na dane dla załączników typu treści

Musisz mieć lokalny zapis wszystkich utworzonych załączników. Dzięki temu możesz wyszukać treści wybrane przez nauczyciela za pomocą identyfikatorów udostępnionych przez Classroom.

Skonfiguruj schemat bazy danych dla Attachment. Nasz przykład przedstawia załączniki z obrazem i tytułem. Element Attachment zawiera te atrybuty:

  • attachment_id: unikalny identyfikator załącznika. Przypisany przez Classroom i zwrócony w odpowiedzi podczas tworzenia załącznika.
  • image_filename: lokalna nazwa pliku obrazu, który ma być wyświetlany.
  • image_caption: podpis, który ma być wyświetlany wraz z obrazem.

Python

Rozszerz implementację SQLite i flask_sqlalchemy z poprzednich kroków.

Otwórz plik, w którym zdefiniowano tabelę User (models.pyjeśli korzystasz z naszego przykładu). U dołu pliku poniżej klasy User dodaj te informacje:

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

Zaimportuj nową klasę załącznika do pliku serwera z trasami obsługi załączników.

Konfigurowanie nowych tras

Rozpocznij ten przewodnik, konfigurując nowe strony w naszej aplikacji. Umożliwiają one użytkownikom tworzenie i wyświetlanie treści za pomocą naszego dodatku.

Dodawanie tras tworzenia załączników

Musisz mieć strony, na których nauczyciel będzie mógł wybierać treści i wysyłać prośby o utworzenie załączników. Wdrożyć /attachment-options, aby wyświetlić opcje treści, które nauczyciel może wybrać. Potrzebujesz też szablonów stron wyboru treści i potwierdzenia tworzenia. Nasze przykłady zawierają szablony, a także mogą wyświetlać żądania i odpowiedzi z interfejsu Classroom API.

Zamiast tworzyć nową stronę /attachment-options, możesz zmodyfikować już istniejącą stronę docelową z widokiem karty z informacjami o załączniku, aby wyświetlała opcje treści. Zalecamy utworzenie nowej strony na potrzeby tego ćwiczenia, aby zachować działanie logowania jednokrotnego zaimplementowane w drugim kroku instrukcji, np. odebranie aplikacji uprawnień. Te informacje powinny okazać się przydatne podczas tworzenia i testowania dodatku.

Nauczyciel może wybrać jeden z niewielkich zestawów obrazów z podpisami w naszym przykładzie. Przesłaliśmy 4 zdjęcia znanych zabytków, których podpisy pochodzą z nazwy pliku.

Python

W naszym przykładzie jest to plik 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,
    )

W efekcie pojawi się strona „Tworzenie załączników”:

Widok wyboru treści w przykładowym kodzie Pythona

Nauczyciel może wybrać kilka obrazów. Utwórz 1 załącznik dla każdego obrazu wybranego przez nauczyciela w metodzie create_attachments.

Tworzenie żądań dotyczących tworzenia załączników

Teraz, gdy już wiesz, jakie treści nauczyciel chce załączyć, wyślij żądania do interfejsu Classroom API, aby utworzyć załączniki do projektu. Po otrzymaniu odpowiedzi z interfejsu Classroom API zapisz szczegóły załącznika w bazie danych.

Najpierw pobierz instancję usługi Classroom:

Python

W naszym przykładzie znajduje się on w pliku 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)

Prześlij żądanie CREATE do punktu końcowego courses.courseWork.addOnAttachments. W przypadku każdego obrazu wybranego przez nauczyciela najpierw utwórz obiekt AddOnAttachment:

Python

W naszym przykładzie jest to kontynuacja metody 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}",
    }

W przypadku każdego załącznika musisz podać co najmniej pola teacherViewUri, studentViewUrititle. Wartości teacherViewUri i studentViewUri reprezentują adresy URL wczytywane po otwarciu załącznika przez odpowiedniego użytkownika.

Wysyłaj obiekt AddOnAttachment w treści żądania do odpowiedniego punktu końcowego addOnAttachments. W każdym żądaniu podaj identyfikatory courseId, itemId, itemTypeaddOnToken.

Python

W naszym przykładzie jest to kontynuacja metody 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()

Utwórz w swojej lokalnej bazie danych wpis dotyczący tego załącznika, aby później móc załadować prawidłowe treści. Classroom zwraca w odpowiedzi na żądanie utworzenia unikalną wartość id, dlatego użyj jej jako klucza podstawowego w naszej bazie danych. Pamiętaj też, że Classroom przekazuje parametr zapytania attachmentId podczas otwierania widoku nauczyciela i ucznia:

Python

W naszym przykładzie jest to kontynuacja metody 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()

W tym miejscu rozważ przekierowanie użytkownika na stronę potwierdzenia, na której potwierdzi on, że udało mu się utworzyć załączniki.

Zezwalanie na załączniki z dodatku

Teraz jest dobry moment, aby dodać odpowiednie adresy do pola Dozwolone załączniki: prefiksy URI w sekcji Konfiguracja aplikacji w pakiecie SDK Google Workspace Marketplace. Twój dodatek może tworzyć załączniki tylko z jednego z prefiksów identyfikatorów URI wymienionych na tej stronie. Jest to środek bezpieczeństwa, który pomaga zmniejszyć ryzyko ataków typu „man in the middle”.

Najprostszym sposobem jest podanie w tym polu domeny najwyższego poziomu, np. https://example.com. https://localhost:<your port number>/ działa, jeśli jako serwer WWW używasz komputera lokalnego.

Dodawanie tras dla widoku nauczyciela i ucznia

Istnieją 4 ramki iframe, w których można wczytać dodatek do Google Classroom. Do tej pory zostały utworzone tylko trasy, które wyświetlają iframe widoku Discovery z załącznikiem. Następnie dodaj ścieżki, aby wyświetlać ramki iframe widoku nauczyciela i ucznia.

Ramka iframe widoku nauczyciela jest wymagana, aby wyświetlić podgląd interfejsu ucznia, ale opcjonalnie może zawierać dodatkowe informacje lub funkcje edycji.

Widok ucznia to strona, która wyświetla się każdemu uczniowi po otwarciu załącznika dodatku.

Na potrzeby tego ćwiczenia utwórz jedną /load-content-attachmenttrasę, która będzie widoczna zarówno w widoku nauczyciela, jak i ucznia. Użyj metod interfejsu Classroom API, aby określić, czy użytkownik jest nauczycielem czy uczniem, gdy wczytuje się strona.

Python

W naszym przykładzie jest to plik 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")

Pamiętaj, że w tym momencie musisz też uwierzytelnić użytkownika. Musisz też obsłużyć parametr zapytania login_hint i w razie potrzeby przekierować użytkownika do procesu autoryzacji. Więcej informacji o tym procesie znajdziesz w instrukcjach logowania, które omawialiśmy w poprzednich samouczkach.

Następnie prześlij żądanie do punktu końcowego getAddOnContext odpowiadającego rodzajowi produktu.

Python

W naszym przykładzie jest to kontynuacja metody 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()

Ta metoda zwraca informacje o roli bieżącego użytkownika w klasie. Zmieniać widok wyświetlany użytkownikowi w zależności od jego roli. W obiekcie odpowiedzi wypełnione jest dokładnie jedno z pol studentContext lub teacherContext. Przejrzyj je, aby ustalić, jak zwrócić się do użytkownika.

W każdym przypadku użyj wartości parametru zapytania attachmentId, aby określić, który załącznik ma zostać pobrany z naszej bazy danych. Ten parametr zapytania jest podawany podczas otwierania identyfikatorów URI widoku nauczyciela lub ucznia.

Python

W naszym przykładzie jest to kontynuacja metody 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)

Testowanie dodatku

Aby przetestować tworzenie załączników:

  • Zaloguj się w [Google Classroom] jako jeden z Twoich użytkowników testowych Nauczyciel.
  • Przejdź do karty Zadania i utwórz nowe projekty.
  • Kliknij przycisk Dodatki pod obszarem tekstowym, a następnie wybierz dodatek. Otworzy się iframe, a dodatek wczyta URI konfiguracji załącznika określony na stronie Konfiguracja aplikacji pakietu SDK Google Workspace Marketplace.
  • Wybierz treść, który chcesz dołączyć do projektu.
  • Zamknij iframe po zakończeniu procesu tworzenia załącznika.

W interfejsie tworzenia projektu w Google Classroom powinna pojawić się karta załącznika. Kliknij kartę, aby otworzyć iframe widoku nauczyciela i sprawdzić, czy wyświetla się prawidłowe załącznik. Kliknij przycisk Przypisz.

Aby przetestować doświadczenie ucznia:

  • Następnie zaloguj się w Classroom jako użytkownik testowy będący uczniem w tej samej lekcji co użytkownik testowy będący nauczycielem.
  • Znajdź projekt testu na karcie Zadania.
  • Rozwiń projekt i kliknij kartę załącznika, aby otworzyć kartę widoku ucznia.

Sprawdź, czy dla ucznia wyświetla się prawidłowy załącznik.

Gratulacje! Możesz przejść do następnego kroku, czyli tworzenia załączników typu aktywność.