활동 유형 첨부파일

이 가이드는 클래스룸 부가기능 둘러보기 시리즈의 다섯 번째 둘러보기입니다.

이 둘러보기에서는 이전 둘러보기 단계의 예를 수정하여 활동 유형 연결을 생성합니다. 이러한 첨부파일은 학생 제출이 필요한 첨부파일입니다(예: 서면 응답, 퀴즈 또는 기타 학생 생성 아티팩트).

콘텐츠 유형 첨부파일과 활동 유형 첨부파일의 구별은 중요합니다. 활동 유형 첨부파일은 다음과 같은 점에서 콘텐츠 유형과 다릅니다.

  • 학생 보기 iframe의 오른쪽 상단에 '제출' 버튼이 표시됩니다.
  • 학생 과제물에 고유 식별자를 제공합니다.
  • 학생의 첨부파일 카드가 클래스룸 채점자 UI에 표시됩니다.
  • 학생은 자신이 속한 과제에 대해 성적을 설정할 수 있습니다.

채점에 관한 설명은 다음 둘러보기를 참고하세요. 이 둘러보기에서는 다음을 완료합니다.

  • Classroom API의 이전 첨부파일 생성 요청을 수정하여 활동 유형 첨부파일을 만듭니다.
  • 학생 제출물을 위한 영구 스토리지 구현
  • 이전 학생 뷰 경로를 수정하여 학생의 입력을 수락합니다.
  • 학생 과제물 검토 iframe을 게재할 경로를 제공합니다.

완료한 후에는 교사로 로그인한 상태에서 Google 클래스룸 UI를 통해 과제에 활동 유형의 첨부파일을 만들 수 있습니다. 수업에 참여하는 학생도 iframe에서 활동을 완료하고 응답을 제출할 수 있습니다. 교사는 클래스룸 채점 UI에서 학생의 제출물을 볼 수 있습니다.

이 예에서는 유명한 명소의 이미지와 랜드마크의 이름이 포함된 캡션을 보여주는 이전 둘러보기의 첨부파일 템플릿을 다시 사용합니다. 활동은 학생에게 랜드마크의 이름을 제공하도록 요청하는 메시지로 구성됩니다.

연결 생성 요청 수정

이전 둘러보기에서 콘텐츠 유형 연결을 만든 코드 섹션으로 이동합니다. 여기서 키 항목은 이전에 연결의 teacherViewUri, studentViewUri, title를 지정한 AddOnAttachment 객체의 인스턴스입니다.

모든 부가기능 연결에는 이 세 개의 필드가 필요하지만 studentWorkReviewUri의 존재 여부에 따라 첨부파일이 activity-type인지 content-type인지 결정됩니다. studentWorkReviewUri가 채워진 CREATE 요청은 활동 유형 첨부파일이 되는 반면, studentWorkReviewUri가 없는 CREATE 요청은 콘텐츠 유형 첨부파일이 됩니다.

이 요청을 수정해야 하는 유일한 수정은 studentWorkReviewUri 필드를 채우는 것입니다. 여기에 적절한 이름의 경로를 추가하고 이후 단계에서 구현합니다.

Python

제공된 예에서는 webapp/attachment_routes.py 파일의 create_attachments 메서드에 있습니다.

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}",
}

콘텐츠 유형 첨부파일을 위한 영구 스토리지 추가

활동에 대한 학생의 반응을 기록합니다. 나중에 교사가 학생 과제물 검토 iframe에서 제출물을 확인하면 이를 찾아볼 수 있습니다.

Submission의 데이터베이스 스키마를 설정합니다. 제공된 예에서 학생은 이미지에 표시된 랜드마크의 이름을 입력해야 합니다. 따라서 Submission에는 다음 속성이 포함됩니다.

  • attachment_id: 첨부파일의 고유 식별자입니다. 클래스룸에서 할당되고 연결을 만들 때 응답에서 반환됩니다.
  • submission_id: 학생 제출물의 식별자입니다. 클래스룸에서 할당되고 학생 뷰의 getAddOnContext 응답에 반환됩니다.
  • student_response: 학생이 제공한 답변입니다.

Python

이전 단계의 SQLite 및 flask_sqlalchemy 구현을 확장합니다.

이전 테이블을 정의한 파일로 이동합니다(제공된 예를 따르는 경우 models.py). 파일 하단에 다음을 추가합니다.

# 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))

첨부파일 처리 경로가 있는 서버 파일로 새 Submission 클래스를 가져옵니다.

학생 뷰 경로 수정하기

그런 다음 이전의 학생 뷰 경로를 수정하여 작은 양식을 표시하고 학생의 입력을 수락합니다. 이전 둘러보기의 코드 대부분을 재사용할 수 있습니다.

학생 보기의 경로를 제공하는 서버 코드를 찾습니다. 연결을 만들 때 studentViewUri 필드에 지정된 경로입니다. 첫 번째 변경사항은 getAddOnContext 응답에서 submissionId를 추출하는 것입니다.

Python

제공된 예에서는 webapp/attachment_routes.py 파일의 load_activity_attachment 메서드에 있습니다.

# 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")

학생 제출 상태를 확인해 달라고 요청할 수도 있습니다. 응답에는 학생이 첨부파일을 열었는지 또는 제출했는지와 같은 상태를 나타내는 SubmissionState 값이 포함됩니다. 제출된 제출물의 수정을 허용하지 않거나 교사에게 학생의 진행 상황에 관한 유용한 정보를 제공하려는 경우 유용할 수 있습니다.

Python

제공된 예에서는 위의 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()

마지막으로 데이터베이스에서 연결 정보를 가져와 입력 양식을 제공합니다. 제공된 예의 양식은 문자열 입력 필드와 제출 버튼으로 구성됩니다. 랜드마크 이미지를 표시하고 학생에게 이름을 입력하도록 요청합니다. 응답을 제공하면 데이터베이스에 기록합니다.

Python

제공된 예에서는 위의 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)

사용자를 구분하려면 제출 기능을 사용 중지하고 대신 교사 뷰에 정답을 표시하는 것이 좋습니다.

학생 과제물 검토 iframe의 경로 추가하기

마지막으로 학생 과제물 검토 iframe을 게재할 경로를 추가합니다. 이 경로의 이름은 연결을 만들 때 studentWorkReviewUri에 제공한 이름과 일치해야 합니다. 이 경로는 교사가 클래스룸 채점자 UI에서 학생 제출물을 볼 때 열립니다.

클래스룸에서 학생 과제물 검토 iframe을 열면 submissionId 쿼리 매개변수가 수신됩니다. 이를 사용하여 로컬 데이터베이스에서 학생의 과제물을 가져옵니다.

Python

제공된 예에서는 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)

부가기능 테스트

이전 둘러보기의 부가기능 테스트 단계를 반복합니다. 학생이 열 수 있는 첨부파일이 있어야 합니다.

활동 연결을 테스트하려면 다음 단계를 완료하세요.

  • 교사 테스트 사용자와 같은 수업에 있는 학생 테스트 사용자 중 하나로 Google 클래스룸에 로그인합니다.
  • 수업 과제 탭으로 이동하여 테스트 과제를 펼칩니다.
  • 부가기능 첨부파일 카드를 클릭하여 학생 뷰를 열고 활동에 대한 응답을 제출합니다.
  • 활동을 완료한 후 iframe을 닫습니다. 필요한 경우 제출 버튼을 클릭합니다.

활동을 완료한 후 클래스룸에 변경되는 사항이 없습니다. 이제 학생 과제물 검토 iframe을 테스트합니다.

  • 교사 테스트 사용자로 클래스룸에 로그인합니다.
  • 성적 탭에서 테스트 과제의 열을 찾습니다. 테스트 할당의 이름을 클릭합니다.
  • 테스트 학생 사용자의 카드를 찾습니다. 카드의 첨부파일을 클릭합니다.

학생에게 올바른 제출물이 표시되는지 확인합니다.

수고하셨습니다 다음 단계인 첨부파일 성적 동기화를 진행할 준비가 되었습니다.