활동 유형 첨부파일

이 워크스루는 클래스룸 부가기능 워크스루 시리즈의 다섯 번째 워크스루입니다.

이 워크스루에서는 이전 워크스루 단계의 예시를 수정하여 활동 유형 첨부파일을 만듭니다. 서면 응답, 퀴즈 또는 기타 학생이 생성한 아티팩트와 같이 학생 제출이 필요한 모든 첨부파일입니다.

콘텐츠 유형과 활동 유형 첨부파일을 구분하는 것은 중요합니다. 활동 유형 첨부파일은 콘텐츠 유형 첨부파일과 다음과 같은 차이점이 있습니다.

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

채점에 관한 설명은 다음 워크스루를 참고하세요. 이 워크스루에서는 다음을 완료합니다.

  • 활동 유형 첨부파일을 만들기 위해 이전 첨부파일 생성 요청을 Classroom API로 수정합니다.
  • 학생 제출물을 위한 영구 스토리지 구현
  • 학생 입력을 허용하도록 이전 학생 보기 경로를 수정합니다.
  • 학생 과제물 리뷰 iframe을 게재할 경로를 제공합니다.

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

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

첨부파일 생성 요청 수정

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

모든 부가기능 첨부파일에는 이 세 필드가 필요하지만 studentWorkReviewUri의 유무에 따라 첨부파일이 활동 유형인지 콘텐츠 유형인지 결정됩니다. 채워진 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()

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

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을 닫습니다. 원하는 경우 Turn In 버튼을 클릭합니다.

활동을 완료한 후에도 클래스룸에 변화가 표시되지 않습니다. 이제 학생 과제물 검토 iframe을 테스트합니다.

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

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

축하합니다. 이제 다음 단계인 첨부파일 성적 동기화를 진행할 수 있습니다.