Załączniki typu aktywności

To piąta instrukcja z serii instrukcji dotyczących dodatków do Classroom.

W tym przewodniku zmodyfikujesz przykład z poprzedniego kroku, aby utworzyć załącznik typu aktywność. Są to wszystkie załączniki, które wymagają przesłania przez ucznia, np. pisemnej odpowiedzi, testu lub innego materiału utworzonego przez ucznia.

Rozróżnienie między załącznikami typu treść a załącznikami typu aktywność jest ważne. Załączniki typu aktywności różnią się od załączników typu treści w tych aspektach:

  • W prawym górnym rogu elementu iframe Widok ucznia pojawi się przycisk „Prześlij”.
  • Zawierają one niepowtarzalny identyfikator pracy ucznia.
  • Karta załącznika pojawi się w interfejsie narzędzia do oceniania w Classroom.
  • Mogą ustawić ocenę projektu, do którego należą.

Więcej informacji o ocenianiu znajdziesz w następnym przewodniku. W ramach tego przewodnika wykonasz te czynności:

  • Zmodyfikuj poprzednie żądania utworzenia załącznika w interfejsie Classroom API, aby utworzyć załącznik typu aktywność.
  • Wdrożenie pamięci trwałej dla przesłanych prac uczniów.
  • Zmodyfikuj poprzednią ścieżkę widoku ucznia, aby akceptować dane wejściowe ucznia.
  • Podaj ścieżkę do wyświetlania elementu iframe Sprawdzanie zadań uczniów.

Po zakończeniu tego procesu możesz tworzyć załączniki typu aktywność w projektach w interfejsie Google Classroom po zalogowaniu się jako nauczyciel. Uczniowie w klasie mogą również wykonać ćwiczenie w elemencie iframe i przesłać odpowiedź. Nauczyciel może wyświetlić zadanie ucznia w interfejsie oceniania Classroom.

Na potrzeby tego przykładu użyj ponownie szablonu załącznika z poprzedniego przewodnika, który zawiera obraz znanego zabytku i podpis z jego nazwą. Zadanie polega na poproszeniu ucznia o podanie nazwy punktu orientacyjnego.

Zmiana prośby o utworzenie załącznika

Przejdź do sekcji kodu, w której w poprzednim przewodniku utworzono załącznik typu content-type. Kluczowym elementem jest tu instancja obiektu AddOnAttachment, w której wcześniej określiliśmy atrybuty teacherViewUri, studentViewUri i title załącznika.

Wszystkie załączniki dodatków wymagają tych 3 pól, ale obecność lub brak studentWorkReviewUri określa, czy załącznik jest typu aktywności czy typu treści. CREATE Prośba z wypełnionym polemstudentWorkReviewUri staje się załącznikiem typu aktywność, a CREATEprośba bez wypełnionego polastudentWorkReviewUri staje się załącznikiem typu treść.

Jedyną zmianą, jaką należy wprowadzić w tym żądaniu, jest wypełnienie pola studentWorkReviewUri. Dodaj tutaj odpowiednio nazwaną trasę. Zaimplementujesz ją w późniejszym kroku.

Python

W naszym przykładzie jest to metoda 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 trwałego miejsca na dane do 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 sprawdzania prac uczniów.

Skonfiguruj schemat bazy danych dla Submission. W podanym przykładzie oczekujemy, że uczniowie wpiszą nazwę punktu orientacyjnego widocznego na obrazie. Submission zawiera więc te atrybuty:

  • attachment_id: unikalny identyfikator załącznika. Przypisany przez Classroom i zwracany w odpowiedzi podczas tworzenia załącznika.
  • submission_id: identyfikator przesłanego przez ucznia zadania. Przypisane przez Classroom i zwrócone w getAddOnContextodpowiedzi w widoku ucznia.
  • student_response: odpowiedź podana przez 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). Na końcu pliku dodaj te wiersze:

# 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 trasami obsługi załączników.

Modyfikowanie trasy w widoku ucznia

Następnie zmodyfikuj poprzednią ścieżkę widoku ucznia, aby wyświetlać mały formularz i akceptować dane wejściowe od ucznia. Możesz ponownie wykorzystać większość kodu z poprzedniego przewodnika.

Znajdź kod serwera, który zawiera ścieżkę do widoku ucznia. Jest to ścieżka określona w polu studentViewUri podczas tworzenia załącznika. Pierwszą zmianą, jaką należy wprowadzić, jest wyodrębnienie submissionIdgetAddOnContext odpowiedzi.

Python

W podanym przykładzie jest to metoda 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ż wysłać prośbę o uzyskanie stanu przesłania przez ucznia. Odpowiedź zawiera wartość SubmissionState, która wskazuje stany, np. czy uczeń otworzył załącznik lub oddał pracę. Może to być przydatne, jeśli chcesz uniemożliwić edytowanie oddanego projektu lub jeśli chcesz uzyskać wgląd w postępy uczniów:

Python

W podanym przykładzie jest to kontynuacja metody load_activity_attachment powyżej.

# 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 pobierz informacje o załączniku z naszej bazy danych i wyświetl formularz wejściowy. Formularz w naszym przykładzie składa się z pola wprowadzania ciągu znaków i przycisku przesyłania. Wyświetl obraz punktu orientacyjnego i poproś ucznia o wpisanie jego nazwy. Gdy użytkownik odpowie, zapisz jego odpowiedź w naszej bazie danych.

Python

W podanym przykładzie jest to kontynuacja metody load_activity_attachment powyżej.

# 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świetlić prawidłową odpowiedź w widoku nauczyciela.

Dodawanie trasy do elementu iframe sprawdzania zadań uczniów

Na koniec dodaj ścieżkę do wyświetlania elementu iframe z informacjami o sprawdzaniu prac uczniów. Nazwa tej trasy powinna być zgodna z nazwą podaną w przypadku parametru studentWorkReviewUri podczas tworzenia załącznika. Ta ścieżka otwiera się, gdy nauczyciel wyświetla projekt przesłany przez ucznia w interfejsie oceniania w Classroom.

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

Python

W naszym przykładzie jest to plik 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. Powinien zawierać załącznik, który uczeń może otworzyć.

Aby przetestować załącznik do aktywności:

  • Zaloguj się w Google Classroom jako jeden z uczniów testowych w tej samej klasie co nauczyciel testowy.
  • Przejdź na kartę Zadania i rozwiń projekt testowy.
  • Kliknij kartę załącznika dodatku, aby otworzyć widok ucznia i przesłać odpowiedź na aktywność.
  • Po zakończeniu aktywności zamknij element iframe. Opcjonalnie kliknij przycisk Prześlij.

Po wykonaniu zadania nie powinny wystąpić żadne zmiany w Classroom. Teraz przetestuj element iframe sprawdzania zadań uczniów:

  • Zaloguj się w Classroom jako nauczyciel testowy.
  • Na karcie Oceny znajdź kolumnę z oceną za test. Kliknij nazwę testu.
  • Znajdź kartę użytkownika testowego. Kliknij załącznik na karcie.

Sprawdź, czy uczeń widzi prawidłowe przesłane zadanie.

Gratulacje! Możesz przejść do następnego kroku: synchronizowania ocen załączników.