Załączniki typu treści

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

Z tego przewodnika 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 klasach. Ten przewodnik obejmuje załączniki treści, które nie wymagają przesłania przez ucznia.

W ramach tego przewodnika wykonaj następujące czynności:

  • Pobierz te dodatkowe parametry zapytania i użyj ich:
    • 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 zajęć w Google Classroom, w których 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 trasy umożliwiające tworzenie załączników oraz wyświetlanie elementów iframe Widoku nauczyciela i ucznia.
  • Wyślij te żądania do interfejsu API dodatków 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 pracy możesz tworzyć załączniki typu treści w projektach w interfejsie 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 dotyczących wyświetlania załączników

Jak wcześniej wspomnieliśmy, Google Classroom przekazuje parametry zapytania podczas wczytywania widoku wykrywania załączników w elemencie iframe:

  • courseId: identyfikator bieżących zajęć 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 określonych działań dodatkowych Classroom.
  • login_hint: identyfikator Google bieżącego użytkownika.

Ten przewodnik dotyczy courseId, itemId, itemType i addOnToken. Zachowuj i przekazuj je podczas wywoływania interfejsu API Classroom.

Tak jak w poprzednim kroku przewodnika, zapisz przekazane wartości parametrów zapytania w naszej sesji. Ważne jest, abyśmy robili to przy pierwszym otwarciu widoku wykrywania załączników, ponieważ jest to jedyna możliwość, która pozwoli Classroom przekazać te parametry 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 naszym 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 rejestr 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 instancji Attachment. Nasz przykładowy przykład zawiera załączniki z obrazem i podpisem. Attachment zawiera te atrybuty:

  • attachment_id: unikalny identyfikator załącznika. Przypisane przez Classroom i zwracane w odpowiedzi podczas tworzenia załącznika.
  • image_filename: lokalna nazwa pliku obrazu do wyświetlenia.
  • image_caption: podpis wyświetlany z obrazem.

Python

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

Przejdź do pliku, w którym masz zdefiniowaną tabelę użytkowników (models.py, jeśli korzystasz z podanego przykładu). Dodaj na dole pliku pod klasą 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))

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

Skonfiguruj nowe trasy

Rozpocznij ten przewodnik od konfiguracji nowych stron 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. Zaimplementuj trasę /attachment-options, aby wyświetlić opcje treści, które nauczyciel może wybrać. Potrzebujesz też szablonów dla stron z potwierdzeniem wyboru treści i tworzenia. W naszych przykładach znajdują się szablony tych funkcji. Mogą one też wyświetlać żądania i odpowiedzi z interfejsu Classroom API.

Zamiast tworzyć nową stronę /attachment-options, możesz zmodyfikować istniejącą stronę docelową widoku wykrywania załączników, tak aby zawierała opcje treści. Na potrzeby tego ćwiczenia zalecamy utworzenie nowej strony, aby zachować działanie logowania jednokrotnego zaimplementowane w drugim kroku przewodnika, na przykład cofnięcie uprawnień aplikacji. Powinny one być przydatne podczas tworzenia i testowania dodatku.

Nauczyciel może wybrać z małego zestawu obrazów z podpisami z podanego przykładu. Udostępniliśmy 4 zdjęcia słynnych punktów orientacyjnych, których podpisy pochodzą z nazw plików.

Python

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

Zostanie wyświetlona strona „Utwórz załączniki”, która będzie przypominać tę stronę:

Widok wyboru treści przykładowej w Pythonie

Nauczyciel może wybrać wiele obrazów. Utwórz jeden 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.

Zacznij od pobrania instancji 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)

Wyś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 podanym 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}",
    }

Każdy przyłącze musi zawierać przynajmniej pola teacherViewUri, studentViewUri i title. Elementy teacherViewUri i studentViewUri reprezentują adresy URL, które są wczytywane po otwarciu załącznika przez odpowiedni typ użytkownika.

Wyślij 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 podanym 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 wpis dla tego przyłącza w lokalnej bazie danych, aby móc później wczytać odpowiednią zawartość. 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 po otwarciu widoków Nauczyciel i Uczniowie:

Python

W podanym 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()

Rozważ przekierowanie użytkownika na stronę potwierdzenia z potwierdzeniem utworzenia załączników.

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. Dodatek może tworzyć załączniki tylko z jednego z prefiksów URI wymienionych na tej stronie. To zabezpieczenie zmniejszające 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 w widoku nauczyciela i ucznia

W składni mogą być 4 elementy iframe, w których może zostać załadowany dodatek do Google Classroom. Do tej pory utworzono tylko trasy, które obsługują element iframe widoku wykrywania załączników. Następnie dodaj trasy, które będą wyświetlać elementy iframe widoku nauczyciela i ucznia.

Element iframe Widok nauczyciela jest wymagany do wyświetlenia podglądu doświadczenia ucznia, ale 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ą trasę /load-content-attachment, która obejmuje zarówno widok nauczyciela, jak i ucznia. Użyj metod interfejsu Classroom API, aby określić, czy po załadowaniu strony użytkownik jest nauczycielem czy uczniem.

Python

W naszym przykładzie znajduje się to 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 na tym etapie musisz także uwierzytelnić użytkownika. Obsługuj też tutaj parametr zapytania login_hint i w razie potrzeby skieruj użytkownika do procesu autoryzacji. Więcej informacji o tym procesie znajdziesz we wskazówkach dotyczących logowania omówionych w poprzednich przewodnikach.

Następnie wyślij do punktu końcowego getAddOnContext żądanie zgodne z typem elementu.

Python

W podanym 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",
    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()

Ta metoda zwraca informacje o roli bieżącego użytkownika w zajęciach. 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. Sprawdź je, aby dowiedzieć się, jak zwracać się do użytkownika.

W każdym przypadku użyj wartości parametru zapytania attachmentId, aby wiedzieć, który załącznik pobrać z naszej bazy danych. Ten parametr zapytania jest podawany przy otwieraniu 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 użytkowników testowych Nauczyciela.
  • Otwórz kartę Zadania i utwórz nowy projekt.
  • Kliknij przycisk Dodatki pod obszarem tekstowym, a następnie wybierz dodatek. Element iframe otworzy się, a dodatek wczyta identyfikator URI konfiguracji załączników określony na stronie Konfiguracja aplikacji pakietu SDK Google Workspace Marketplace.
  • Wybierz treść, którą chcesz dołączyć do projektu.
  • Po zakończeniu procesu tworzenia załącznika zamknij element iframe.

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

Aby przetestować działanie interfejsu ucznia, wykonaj te czynności:

  • 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ć element iframe widoku ucznia.

Sprawdź, czy uczniowi wyświetla się właściwy załącznik.

Gratulacje! Możesz teraz przejść do następnego kroku: tworzenia załączników typu działania.