Załączniki typu treści

To czwarty przewodnik z serii dodatków do Classroom.

Z tego przewodnika dowiesz się, jak tworzyć załączniki przy użyciu interfejsu Google Classroom API. Określasz trasy, które umożliwiają użytkownikom wyświetlenie zawartości załącznika. Widoki te różnią się w zależności od roli użytkownika w zajęciach. Ten przewodnik dotyczy załączników o typie treści, które nie wymagają przesyłania przez ucznia.

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

  • Pobierz i używaj tych dodatkowych parametrów zapytania:
    • addOnToken: token autoryzacji przekazany do widoku wykrywania załączników.
    • itemId: unikalny identyfikator CourseWork, CourseWorkMaterial lub ogłoszenia, który otrzymuje załącznik dodatku.
    • itemType: „courseWork”, „courseWorkMaterials” lub „ogłoszenie”.
    • courseId: unikalny identyfikator zajęć w Google Classroom, w których tworzony jest projekt.
    • attachmentId: unikalny identyfikator przypisywany przez Google Classroom do załącznika dodatku po jego utworzeniu.
  • Zaimplementuj pamięć trwałą dla załączników typu treści.
  • Podaj trasy do tworzenia załączników oraz wyświetlania elementów iframe widoku nauczyciela i widoku ucznia.
  • Wyślij te żądania do interfejsu Google Classroom dodatków API:
    • Utwórz nowy załącznik.
    • Pobierz kontekst dodatku, który wskazuje, czy zalogowany użytkownik jest uczniem czy nauczycielem.

Gdy skończysz, po zalogowaniu się jako nauczyciel możesz tworzyć załączniki do projektów w interfejsie Google Classroom. Nauczyciele i uczniowie na zajęciach również mogą je przeglądać.

Włączanie interfejsu Classroom API

Wykonaj wywołania interfejsu Classroom API, zaczynając od tego kroku. Aby można było wywoływać ten interfejs API, musi on być włączony w projekcie Google Cloud. Przejdź do wpisu biblioteki interfejsu Google Classroom API i wybierz Włącz.

Obsługa parametrów zapytania widoku Wykrywanie załączników

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

  • courseId: identyfikator bieżących zajęć w Classroom.
  • itemId: unikalny identyfikator CourseWork, CourseWorkMaterial lub ogłoszenia, który otrzymuje załącznik dodatku.
  • itemType: „courseWork”, „courseWorkMaterials” lub „ogłoszenie”.
  • addOnToken: token używany do autoryzacji określonych działań dodatków do Classroom.
  • login_hint: identyfikator Google bieżącego użytkownika.
  • hd: domena hosta bieżącego użytkownika, na przykład example.com.

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

Tak jak w poprzednim kroku przewodnika, przekazane wartości parametrów zapytania będą przechowywane w naszej sesji. Pamiętaj, aby zrobić to przy pierwszym otwarciu widoku Odkrywanie załączników, ponieważ jest to jedyna możliwość przekazania tych parametrów zapytania w Classroom.

Python

Przejdź do pliku serwera Flask, który zawiera trasy widoku wykrywania załączników (attachment-discovery-routes.py, jeśli korzystasz z naszego przykładu). Na górze trasy docelowej dodatku (w tym przykładzie /classroom-addon) pobierz i zapisz parametry zapytania courseId, itemId, itemType i 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 zostaną obecne. Nie zostaną one ponownie przesłane, jeśli użytkownik wróci później do widoku wykrywania załączników bez zamykania elementu iframe.

Dodaj pamięć trwałą dla załączników typu treści

Musisz mieć lokalny rejestr 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 podpisem. Attachment zawiera te atrybuty:

  • attachment_id: unikalny identyfikator załącznika. Przypisywane 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 jest zdefiniowana tabela użytkowników (models.py, jeśli korzystasz z podanego przykładu). Dodaj poniższy kod 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ę załączników do pliku serwera z trasami obsługi załączników.

Skonfiguruj nowe trasy

Ten przewodnik zacznij od skonfigurowania nowych stron w aplikacji. Te opcje pozwalają użytkownikowi tworzyć i wyświetlać treści za pomocą naszego dodatku.

Dodawanie tras tworzenia załączników

Nauczyciel potrzebuje stron, na których może wybierać treści i przesyłać prośby o utworzenie załączników. Zaimplementuj trasę /attachment-options, aby wyświetlić opcje treści, które nauczyciel może wybrać. Potrzebne są też szablony stron wyboru treści i potwierdzenia utworzenia. Udostępnione przez nas 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 też zmodyfikować istniejącą stronę docelową widoku Odkrywanie załączników, tak aby wyświetlały się opcje treści. Zalecamy utworzenie nowej strony na potrzeby tego ćwiczenia, aby zachować działanie logowania jednokrotnego zaimplementowane w drugim kroku, takie jak anulowanie uprawnień aplikacji. Powinny one być przydatne podczas tworzenia i testowania dodatku.

Nauczyciel może wybrać spośród małego zestawu obrazów z podpisami, które podajemy w podanym przez nas przykładzie. Dostarczyliśmy cztery obrazy przedstawiające znane punkty orientacyjne, których podpisy pochodzą z nazw plików.

Python

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

Zostanie utworzona strona „Create Attachments” (Utwórz załączniki), która będzie przypominać tę stronę:

Przykładowy widok wyboru treści w Pythonie

Nauczyciel może wybrać wiele obrazów. Utwórz po jednym załączniku do każdego obrazu wybranego przez nauczyciela za pomocą metody create_attachments.

Problemy z żądaniami utworzenia załączników

Gdy już wiesz, które materiały nauczyciel chce dołączyć do projektu, możesz wysłać do interfejsu Classroom API żądania utworzenia załączników do zadania. Przechowuj szczegóły załączników w bazie danych po otrzymaniu odpowiedzi z interfejsu Classroom API.

Zacznij od pobrania instancji usługi Classroom:

Python

W podanym 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.
    # We need to request the Classroom API from a specific URL while add-ons
    # are in Early Access.

    # A Google API Key can be created in your Google Cloud project's Credentials
    # settings: https://console.cloud.google.com/apis/credentials.
    # Click "Create Credentials" at top and choose "API key", then provide
    # the key in the discoveryServiceUrl below.
    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)

Wyślij żądanie CREATE do punktu końcowego courses.courseWork.addOnAttachments. Dla każdego obrazu wybranego przez nauczyciela utwórz najpierw 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}",
    }

W przypadku każdego załącznika należy podać co najmniej pola teacherViewUri, studentViewUri i title. teacherViewUri i studentViewUri wskazują adresy URL, które są ładowane w momencie otwarcia załącznika przez określony typ użytkownika.

Wyślij obiekt AddOnAttachment w treści żądania do odpowiedniego punktu końcowego addOnAttachments. W 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ć prawidłową treść. Classroom zwraca w odpowiedzi na żądanie utworzenia unikalną wartość id, więc używaj jej jako klucza podstawowego w naszej bazie danych. Pamiętaj też, że Classroom przekazuje parametr zapytania attachmentId po otwarciu widoku nauczyciela i ucznia:

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 poziomu dodatku

Teraz jest dobra okazja do dodania odpowiednich adresów w polu Dozwolone prefiksy identyfikatora URI załączników na stronie konfiguracji aplikacji pakietu GWM SDK. Twój dodatek może tworzyć załączniki tylko z jednego z prefiksów URI wymienionych na tej stronie. To zabezpieczenie, które zmniejsza 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>/ działa, jeśli jako serwera WWW używasz komputera lokalnego.

Dodawanie tras w widokach nauczyciela i uczniów

Istnieją 4 elementy iframe, w których może się załadować dodatek Google Classroom. Do tej pory masz utworzone tylko trasy obsługujące element iframe widoku Wykrywanie załączników. Następnie dodaj trasy, aby wyświetlać również elementy iframe widoku nauczyciela i ucznia.

Element iframe Widok nauczyciela jest wymagany do wyświetlania podglądu 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.

Dla celów tego ćwiczenia utwórz 1 trasę /load-content-attachment dla widoku nauczyciela i ucznia. Za pomocą metod interfejsu Classroom API można określić, czy użytkownik jest nauczycielem czy uczniem podczas wczytywania strony.

Python

W podanym 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 na tym etapie musisz też uwierzytelnić użytkownika. W tym miejscu musisz też obsłużyć parametry zapytania login_hint i hd i w razie potrzeby przekierować użytkownika do procesu autoryzacji. Więcej informacji o tym procesie znajdziesz w szczegółach wskazówek dotyczących logowania omówionych w poprzednich instrukcjach.

Następnie wyślij żądanie do punktu końcowego getAddOnContext pasującego do typu 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. Obiekt odpowiedzi zawiera dokładnie jedno z pól studentContext lub teacherContext. Zapoznaj się z nimi, aby określić, jak zwrócić się do użytkownika.

W każdym przypadku użyj wartości parametru zapytania attachmentId, aby dowiedzieć się, który załącznik pobrać z naszej bazy danych. Ten parametr zapytania jest podawany po otwarciu 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łącznika, 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. Otworzy się element iframe, a dodatek wczyta identyfikator URI konfiguracji załączników podany na stronie Konfiguracja aplikacji w pakiecie GWM SDK.
  • Wybierz treść, którą chcesz dołączyć do projektu.
  • Zamknij element 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ć element iframe Widoku nauczyciela i sprawdzić, czy wyświetla się prawidłowy załącznik. Kliknij przycisk Przypisz.

Aby sprawdzić wrażenia ucznia:

  • Następnie zaloguj się w Classroom jako uczeń testowy na tych samych zajęciach co użytkownik testowy.
  • 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ę prawidłowy załącznik.

Gratulacje! Możesz przejść do kolejnego kroku: tworzenia załączników typu activity.