Załączniki typu treści

To jest czwarty przewodnik z serii przewodników dotyczących dodatków do Classroom.

W tym samouczku dowiesz się, jak tworzyć załączniki za pomocą interfejsu Google Classroom API. Określasz trasy, dzięki którym użytkownicy będą mogli wyświetlić zawartość załącznika. Widoki różnią się w zależności od roli użytkownika w zajęciach. Ten przewodnik obejmuje załączniki treści, które nie wymagają przesłania przez ucznia.

W trakcie tego samouczka wykonasz te czynności:

  • Pobieraj i używaj tych parametrów zapytania dotyczących dodatku:
    • addOnToken: token autoryzacji przekazywany do widoku wykrywania załączników.
    • itemId: unikalny identyfikator elementu CourseWork, CourseWorkMaterial lub ogłoszenia, który otrzymuje 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.
  • Zaimplementuj trwałą pamięć masową dla załączników typu treści.
  • 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. Nauczyciele i uczniowie na zajęciach również mogą wyświetlać te treści.

Włączanie interfejsu Classroom API

Wywołuj interfejs Classroom API, zaczynając od tego kroku. Aby móc wywoływać interfejs API, musisz go włączyć w projekcie Google Cloud. Otwórz wpis biblioteki 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 elementu CourseWork, CourseWorkMaterial lub ogłoszenia, który otrzymuje 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. Zachowuj i przekazuj je podczas wywoływania interfejsu API Classroom.

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

Przejdź do pliku serwera Flask zawierającego trasy dla widoku wykrywania załączników (attachment-discovery-routes.py, jeśli korzystasz z naszego przykładu). Na górze trasy docelowej dodatku (/classroom-addon w podanym przykładzie) pobierz i zapisz parametry zapytania courseId, itemId, itemType oraz 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")

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

Dodaj pamięć trwałą na załączniki typu treści

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

Skonfiguruj schemat bazy danych dla Attachment. Nasz przykład przedstawia załączniki z obrazem i tytułem. 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.

Skonfiguruj nowe trasy

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.

Dodaj trasy tworzenia załączników

Musisz mieć strony, na których nauczyciel wybierze treść i wyśle prośbę o utworzenie załącznika. 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ć na niej opcje treści. Zalecamy utworzenie nowej strony na potrzeby tego ćwiczenia, aby zachować działanie logowania jednokrotnego zaimplementowane w drugim kroku instrukcji, np. cofnięcie uprawnień aplikacji. 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 z podpisami pochodzącymi z nazwy pliku.

Python

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

Wyświetli się strona „Utwórz załączniki” podobna do tej:

Widok wyboru treści przykładowej w Pythonie

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

Prośby o utworzenie załączników dotyczących problemu

Gdy już wiesz, jakie materiały nauczyciel chce dołączyć, wyślij do interfejsu Classroom API prośby o utworzenie załączników 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ę to 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. Dla 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. Elementy teacherViewUri i studentViewUri reprezentują adresy URL, które są wczytywane po otwarciu załącznika przez odpowiedni typ użytkownika.

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

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 przesłać prawidłowe treści. Classroom zwraca unikalną wartość id w odpowiedzi na żądanie utworzenia, więc użyj tej wartości 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ę z potwierdzeniem, 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 w polu Dozwolone prefiksy identyfikatorów URI załączników na stronie Konfiguracja aplikacji pakietu 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, na przykład https://example.com. https://localhost:<your port number>/ będzie działać, jeśli jako serwera WWW używasz komputera lokalnego.

Dodawanie tras dla widoku nauczyciela i ucznia

W których może być załadowany dodatek do Google Classroom, znajdują się 4 elementy iframe. 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 wyświetlana 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 znajduje się on w pliku 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 jest wypełnione dokładnie 1 z pól studentContext lub teacherContext. Przejrzyj je, aby ustalić, jak zwracać 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 podanym 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, wykonaj te czynności:

  • 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 w tych samych zajęciach co nauczyciel.
  • Znajdź projekt testowy 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: tworzenia załączników typu aktywność.