활동 유형 첨부파일

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

이 둘러보기에서는 이전 둘러보기 단계의 예를 수정하여 활동 유형 연결을 만듭니다. 여기에는 서면 응답, 퀴즈 또는 기타 학생 생성 아티팩트와 같이 학생 제출이 필요한 모든 첨부파일이 포함됩니다.

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

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

채점에 대한 논의는 다음 둘러보기를 확인하세요. 이 둘러보기 과정에서 다음을 완료합니다.

  • 클래스룸 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을 닫습니다. 필요한 경우 제출 버튼을 클릭합니다.

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

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

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

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