Załączniki typu aktywności

To piąty przewodnik z serii o dodatkach do Classroom.

W tym przewodniku zmodyfikujesz przykład z poprzedniego kroku, aby uzyskać załącznik typu aktywność. Są to wszystkie załączniki, które wymagają przesłania przez ucznia, takie jak odpowiedź pisemna, test lub inny wytworzony przez ucznia element.

Ważne jest rozróżnienie załączników typu „treści” i „działalność”. Załączniki typu aktywność różnią się od załączników typu treści w tych aspektach:

  • W prawym górnym rogu ramki iframe widoku ucznia pojawi się przycisk „Zgłoś”.
  • Są one unikalnym identyfikatorem zadań uczniów.
  • Karta załącznika pojawi się w interfejsie oceniania w Classroom.
  • Mogą ustawić ocenę projektu, do którego należą.

W następnym samouczku znajdziesz informacje na temat oceniania. W trakcie tego przejścia:

  • Zmodyfikuj poprzednie żądania tworzenia załączników do interfejsu Classroom API, aby utworzyć załącznik typu aktywność.
  • Wdrożyć trwałe miejsce na dane dla prac uczniów.
  • Zmień poprzednią ścieżkę w widoku ucznia, aby umożliwić uczniom wprowadzanie danych.
  • Podaj ścieżkę do wyświetlania ramki iframe Sprawdzanie zadań uczniów.

Po zakończeniu możesz tworzyć załączniki w postaci zajęć w projektach w interfejsie Google Classroom po zalogowaniu się jako nauczyciel. Uczniowie na zajęciach mogą też wykonać zadanie w ramce iframe i przesłać odpowiedź. Nauczyciel może wyświetlić zadanie ucznia w interfejsie oceniania w Classroom.

W tym przykładzie użyj szablonu załącznika z poprzedniego przewodnika, który zawiera zdjęcie słynnego punktu orientacyjnego i podpis z jego nazwą. Uczeń musi podać nazwę zabytku.

Modyfikowanie prośby o utworzenie załącznika

Przejdź do sekcji kodu, w której w poprzednim przewodniku utworzyłeś załącznik z typem treści. Kluczowym elementem jest tu instancja obiektu AddOnAttachment, w którym wcześniej określono atrybuty teacherViewUri, studentViewUrititle dla załącznika.

Wszystkie załączniki dodatków wymagają tych 3 pol, ale obecność lub brak studentWorkReviewUri określa, czy załącznik jest typu aktywność czy typu treść. Prośba CREATE z wypełnionym polem studentWorkReviewUri staje się załącznikiem typu aktywność, a prośba CREATE bez pola studentWorkReviewUri staje się załącznikiem typu treść.

Jedyną zmianą, jaką należy wprowadzić w tym żądaniu, jest wypełnienie pola studentWorkReviewUri. Tutaj dodaj trasę o odpowiedniej nazwie, którą wdrożysz w następnym kroku.

Python

W naszym przykładzie znajduje się ona w metodzie create_attachments w pliku webapp/attachment_routes.py.

attachment = {
    # Specifies the route for a teacher user.
    "teacherViewUri": {
        "uri":
            flask.url_for(
                "load_activity_attachment",
                _scheme='https',
                _external=True),
    },
    # Specifies the route for a student user.
    "studentViewUri": {
        "uri":
            flask.url_for(
                "load_activity_attachment",
                _scheme='https',
                _external=True)
    },
    # Specifies the route for a teacher user when the attachment is
    # loaded in the Classroom grading view.
    # The presence of this field marks this as an activity-type attachment.
    "studentWorkReviewUri": {
        "uri":
            flask.url_for(
                "view_submission", _scheme='https', _external=True)
    },
    # The title of the attachment.
    "title": f"Attachment {attachment_count}",
}

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

Zapisz odpowiedź ucznia na naszą aktywność. Możesz go później sprawdzić, gdy nauczyciel wyświetli przesłane zadanie w ramce iframe Sprawdzanie zadań uczniów.

Skonfiguruj schemat bazy danych dla Submission. W naszym przykładzie uczniowie mają wpisać nazwę zabytku widocznego na obrazie. Element Submission zawiera więc te atrybuty:

  • attachment_id: unikalny identyfikator załącznika. Przypisany przez Classroom i zwrócony w odpowiedzi podczas tworzenia załącznika.
  • submission_id: identyfikator przesłania ucznia. Przypisane przez Classroom i zwrócone w odpowiedzi getAddOnContext w widoku ucznia.
  • student_response: odpowiedź ucznia.

Python

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

Otwórz plik, w którym zdefiniowano poprzednie tabele (models.py, jeśli korzystasz z naszego przykładu). Dodaj te informacje na dole pliku.

# Database model to represent a student submission.
class Submission(db.Model):
    # The attachmentId is the unique identifier for the attachment.
    submission_id = db.Column(db.String(120), primary_key=True)

    # The unique identifier for the student's submission.
    attachment_id = db.Column(db.String(120), primary_key=True)

    # The student's response to the question prompt.
    student_response = db.Column(db.String(120))

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

Modyfikowanie trasy w widoku ucznia

Następnie zmodyfikuj poprzednią ścieżkę w widoku ucznia, aby wyświetlić mały formularz i zaakceptować dane wprowadzone przez ucznia. Większość kodu z poprzedniego samouczka możesz wykorzystać ponownie.

Znajdź kod serwera, który wskazuje trasę dla widoku ucznia. Jest to trasa określona w polu studentViewUri podczas tworzenia załącznika. Pierwszą zmianą, którą należy wprowadzić, jest wyodrębnienie wartości submissionId z odpowiedzi getAddOnContext.

Python

W naszym przykładzie znajduje się ona w metodzie load_activity_attachment w pliku webapp/attachment_routes.py.

# Issue a request to the courseWork.getAddOnContext endpoint
addon_context_response = classroom_service.courses().courseWork(
).getAddOnContext(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"]).execute()

# One of studentContext or teacherContext will be populated.
user_context = "student" if addon_context_response.get(
    "studentContext") else "teacher"

# If the user is a student...
if user_context == "student":
    # Extract the submissionId from the studentContext object.
    # This value is provided by Google Classroom.
    flask.session["submissionId"] = addon_context_response.get(
            "studentContext").get("submissionId")

Możesz też poprosić o status przesłanego zadania. Odpowiedź zawiera wartość SubmissionState, która wskazuje stany takie jak to, czy uczeń otworzył załącznik czy go przesłał. Może to być przydatne, jeśli chcesz zablokować edycję przesłanych prac lub chcesz udostępnić nauczycielom informacje o postępach uczniów:

Python

W tym przykładzie jest to kontynuacja metody load_activity_attachment.

# Issue a request to get the status of the student submission.
submission_response = classroom_service.courses().courseWork(
).addOnAttachments().studentSubmissions().get(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"],
    attachmentId=flask.session["attachmentId"],
    submissionId=flask.session["submissionId"]).execute()

Na koniec pobieramy informacje o załączniku z naszej bazy danych i wyświetlamy formularz wprowadzania danych. Formularz w naszym przykładzie składa się z pola tekstowego i przycisku przesyłania. Pokaż obraz zabytku i poproś ucznia o wpisanie jego nazwy. Gdy otrzymasz odpowiedź, zapisz ją w naszej bazie danych.

Python

W naszym przykładzie jest to kontynuacja metody load_activity_attachment.

# Look up the attachment in the database.
attachment = Attachment.query.get(flask.session["attachmentId"])

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 complete the activity below.")

form = activity_form_builder()

if form.validate_on_submit():
    # Record the student's response in our database.

    # Check if the student has already submitted a response.
    # If so, update the response stored in the database.
    student_submission = Submission.query.get(flask.session["submissionId"])

    if student_submission is not None:
        student_submission.student_response = form.student_response.data
    else:
        # Store the student's response by the submission ID.
        new_submission = Submission(
            submission_id=flask.session["submissionId"],
            attachment_id=flask.session["attachmentId"],
            student_response=form.student_response.data)
        db.session.add(new_submission)

    db.session.commit()

    return flask.render_template(
        "acknowledge-submission.html",
        message="Your response has been recorded. You can close the " \
            "iframe now.",
        instructions="Please Turn In your assignment if you have " \
            "completed all tasks."
    )

# Show the activity.
return flask.render_template(
    "show-activity-attachment.html",
    message=message_str,
    image_filename=attachment.image_filename,
    image_caption=attachment.image_caption,
    user_context=user_context,
    form=form,
    responses=response_strings)

Aby odróżnić użytkowników, możesz wyłączyć funkcję przesyłania i zamiast tego wyświetlać prawidłową odpowiedź w widoku nauczyciela.

Dodawanie trasy dla ramki iframe sprawdzania zadań uczniów

Na koniec dodaj trasę, aby wyświetlać ramkę osadzania zadań uczniów. Nazwa tej trasy powinna być taka sama jak podana w przypadku studentWorkReviewUri podczas tworzenia załącznika. Ta ścieżka otwiera się, gdy nauczyciel wyświetla przesłane przez ucznia zadanie w interfejsie narzędzia do oceniania w Classroom.

Parametr zapytania submissionId otrzymasz, gdy Classroom otworzy iframe Sprawdzania prac uczniów. Użyj go, aby pobrać pracę ucznia z Twojej lokalnej bazy danych:

Python

W naszym przykładzie znajduje się on w pliku webapp/attachment_routes.py.

@app.route("/view-submission")
def view_submission():
    """
    Render a student submission using the show-student-submission.html template.
    """

    # Save the query parameters passed to the iframe in the session, just as we did
    # in previous routes. Abbreviated here for readability.
    add_iframe_query_parameters_to_session(flask.request.args)

    # For the sake of brevity in this example, we'll skip the conditional logic
    # to see if we need to authorize the user as we have done in previous steps.
    # We can assume that the user that reaches this route is a teacher that has
    # already authorized and created an attachment using the add-on.

    # In production, we recommend fully validating the user's authorization at
    # this stage as well.

    # Look up the student's submission in our database.
    student_submission = Submission.query.get(flask.session["submissionId"])

    # Look up the attachment in the database.
    attachment = Attachment.query.get(student_submission.attachment_id)

    # Render the student's response alongside the correct answer.
    return flask.render_template(
        "show-student-submission.html",
        message=f"Loaded submission {student_submission.submission_id} for "\
            f"attachment {attachment.attachment_id}.",
        student_response=student_submission.student_response,
        correct_answer=attachment.image_caption)

Testowanie dodatku

Powtórz kroki testowania dodatku z poprzedniego przewodnika. Uczeń powinien mieć możliwość otwarcia załącznika.

Aby przetestować załącznik aktywności:

  • Zaloguj się w Google Classroom jako jeden z uczniów testowych w tej samej klasie co nauczyciel.
  • Przejdź do karty Zadania i rozwiń test Projekt.
  • Kliknij kartę załącznika dodatku, aby otworzyć widok ucznia i przesłać odpowiedź na zadanie.
  • Po zakończeniu zadania zamknij ramkę iframe. Opcjonalnie kliknij przycisk Włącz.

Po zakończeniu aktywności w Classroom nie powinno się nic zmienić. Teraz przetestuj iframe Sprawdzanie zadań uczniów:

  • Zaloguj się w Classroom jako użytkownik testowy nauczyciel.
  • Znajdź kolumnę z zadaniem testowym na karcie Oceny. Kliknij nazwę testu.
  • Znajdź kartę testowego ucznia. Kliknij załącznik na karcie.

Sprawdź, czy uczniowi wyświetla się prawidłowe zgłoszenie.

Gratulacje! Możesz przejść do następnego kroku: synchronizacji ocen z załącznikami.