Tệp đính kèm loại nội dung

Đây là hướng dẫn thứ tư trong chuỗi hướng dẫn từng bước về tiện ích bổ sung trong Lớp học.

Trong hướng dẫn này, bạn sẽ tương tác với API Google Lớp học để tạo tệp đính kèm. Bạn cung cấp tuyến để người dùng xem nội dung tệp đính kèm. Các khung hiển thị còn tuỳ thuộc vào vai trò của người dùng trong lớp. Hướng dẫn này đề cập đến tệp đính kèm loại nội dung mà không yêu cầu học viên nộp.

Trong quá trình hướng dẫn này, bạn sẽ hoàn thành các bước sau:

  • Truy xuất và sử dụng các tham số truy vấn của tiện ích bổ sung sau đây:
    • addOnToken: Mã thông báo uỷ quyền được chuyển đến Khung hiển thị khám phá tệp đính kèm.
    • itemId: Giá trị nhận dạng duy nhất của CourseWork, CourseWorkMaterial hoặc Thông báo nhận được tệp đính kèm của tiện ích bổ sung.
    • itemType: "courseWork", "courseWorkMaterials" hoặc "thông báo".
    • courseId: Giá trị nhận dạng duy nhất của khoá học Google Lớp học nơi bài tập đang được tạo.
    • attachmentId: Giá trị nhận dạng duy nhất do Google Lớp học gán cho một tệp đính kèm của tiện ích bổ sung sau khi tạo.
  • Triển khai bộ nhớ liên tục cho các tệp đính kèm loại nội dung.
  • Cung cấp các tuyến để tạo tệp đính kèm và phân phát iframe Khung hiển thị của giáo viên và Khung hiển thị của học viên.
  • Gửi các yêu cầu sau đây đến API tiện ích bổ sung Google Lớp học:
    • Tạo tệp đính kèm mới.
    • Nhận ngữ cảnh của tiện ích bổ sung giúp xác định xem người dùng đã đăng nhập là học viên hay giáo viên.

Sau khi hoàn tất, bạn có thể tạo tệp đính kèm loại nội dung trên bài tập thông qua giao diện người dùng của Google Lớp học khi đăng nhập với tư cách là giáo viên. Giáo viên và học viên trong lớp cũng có thể xem nội dung.

Bật API Lớp học

Gọi API Lớp học bắt đầu từ bước này. Bạn phải bật API này cho dự án Google Cloud của mình thì mới có thể thực hiện lệnh gọi đến dự án đó. Chuyển đến mục thư viện của API Google Lớp học rồi chọn Bật.

Xử lý tham số truy vấn Khung hiển thị khám phá tệp đính kèm

Như đã thảo luận trước đó, Google Lớp học sẽ truyền các tham số truy vấn khi tải Chế độ xem khám phá tệp đính kèm trong iframe:

  • courseId: Mã của khoá học hiện tại trên Lớp học.
  • itemId: Giá trị nhận dạng duy nhất của CourseWork, CourseWorkMaterial hoặc Thông báo nhận được tệp đính kèm của tiện ích bổ sung.
  • itemType: "courseWork", "courseWorkMaterials" hoặc "thông báo".
  • addOnToken: Mã thông báo dùng để uỷ quyền một số thao tác nhất định của tiện ích bổ sung cho Lớp học.
  • login_hint: Mã nhận dạng trên Google của người dùng hiện tại.
  • hd: Miền lưu trữ cho người dùng hiện tại, chẳng hạn như example.com.

Hướng dẫn này hướng dẫn courseId, itemId, itemTypeaddOnToken. Giữ lại và truyền các giá trị này khi thực hiện lệnh gọi tới API Lớp học.

Như trong bước hướng dẫn trước đó, hãy lưu trữ các giá trị tham số truy vấn đã chuyển trong phiên hoạt động của chúng ta. Điều quan trọng là chúng ta phải thực hiện việc này khi Chế độ xem khám phá tệp đính kèm được mở lần đầu, vì đây là cơ hội duy nhất để Lớp học truyền các tham số truy vấn này.

Python

Chuyển đến tệp máy chủ Flask, nơi cung cấp các tuyến cho Chế độ xem khám phá tệp đính kèm (attachment-discovery-routes.py nếu bạn đang làm theo ví dụ của chúng tôi). Ở đầu tuyến đích của tiện ích bổ sung (/classroom-addon trong ví dụ của chúng tôi), hãy truy xuất và lưu trữ các tham số truy vấn courseId, itemId, itemTypeaddOnToken.

# Retrieve the itemId, courseId, and addOnToken query parameters.
if flask.request.args.get("itemId"):
    flask.session["itemId"] = flask.request.args.get("itemId")
if flask.request.args.get("itemType"):
    flask.session["itemType"] = flask.request.args.get("itemType")
if flask.request.args.get("courseId"):
    flask.session["courseId"] = flask.request.args.get("courseId")
if flask.request.args.get("addOnToken"):
    flask.session["addOnToken"] = flask.request.args.get("addOnToken")

Chỉ ghi các giá trị này vào phiên nếu sau này có mặt; các giá trị này sẽ không được truyền lại nếu sau này người dùng quay lại Chế độ xem khám phá tệp đính kèm mà không đóng iframe.

Thêm bộ nhớ ổn định cho các tệp đính kèm loại nội dung

Bạn cần có bản ghi cục bộ của mọi tệp đính kèm đã tạo. Việc này cho phép bạn tra cứu nội dung mà giáo viên đã chọn bằng giá trị nhận dạng do Lớp học cung cấp.

Thiết lập giản đồ cơ sở dữ liệu cho Attachment. Ví dụ của chúng tôi trình bày tệp đính kèm có hình ảnh và chú thích. Attachment chứa các thuộc tính sau:

  • attachment_id: Giá trị nhận dạng duy nhất của tệp đính kèm. Do Lớp học chỉ định và trả về trong phản hồi khi tạo tệp đính kèm.
  • image_filename: Tên tệp cục bộ của hình ảnh hiển thị.
  • image_caption: Chú thích sẽ hiển thị cùng với hình ảnh.

Python

Mở rộng việc triển khai SQLite và flask_sqlalchemy từ các bước trước.

Chuyển đến tệp mà bạn đã xác định bảng Người dùng (models.py nếu bạn đang làm theo ví dụ mà chúng tôi cung cấp). Thêm phần sau vào cuối tệp bên dưới lớp User.

class Attachment(db.Model):
    # The attachmentId is the unique identifier for the attachment.
    attachment_id = db.Column(db.String(120), primary_key=True)

    # The image filename to store.
    image_filename = db.Column(db.String(120))

    # The image caption to store.
    image_caption = db.Column(db.String(120))

Nhập lớp Tệp đính kèm mới vào tệp máy chủ bằng các tuyến xử lý tệp đính kèm của bạn.

Thiết lập tuyến đường mới

Bắt đầu bước hướng dẫn này bằng cách thiết lập một số trang mới trong ứng dụng của chúng tôi. Những phần mềm này cho phép người dùng tạo và xem nội dung thông qua tiện ích bổ sung của chúng tôi.

Thêm tuyến tạo tệp đính kèm

Bạn cần có các trang để giáo viên chọn nội dung và gửi yêu cầu tạo tệp đính kèm. Triển khai tuyến /attachment-options để hiển thị các tuỳ chọn nội dung để giáo viên chọn. Bạn cũng cần các mẫu cho trang lựa chọn nội dung và xác nhận tạo. Các ví dụ mà chúng tôi cung cấp có chứa các mẫu cho những trường hợp này và cũng có thể hiển thị các yêu cầu và phản hồi từ API Lớp học.

Xin lưu ý rằng bạn có thể sửa đổi trang đích Chế độ xem khám phá tệp đính kèm hiện có để hiển thị các lựa chọn nội dung thay vì tạo trang /attachment-options mới. Bạn nên tạo một trang mới cho mục đích của bài tập này để duy trì hành vi SSO được triển khai trong bước hướng dẫn thứ hai, chẳng hạn như thu hồi quyền của ứng dụng. Những thông tin này sẽ chứng minh được sự hữu ích khi bạn xây dựng và kiểm thử tiện ích bổ sung của mình.

Giáo viên có thể chọn trong một nhóm nhỏ các hình ảnh có chú thích trong ví dụ chúng tôi cung cấp. Chúng tôi đã cung cấp 4 hình ảnh về các địa danh nổi tiếng có chú thích được lấy từ tên tệp.

Python

Trong ví dụ chúng tôi cung cấp, phần phụ thuộc nằm trong tệp webapp/attachment_routes.py.

@app.route("/attachment-options", methods=["GET", "POST"])
def attachment_options():
    """
    Render the attachment options page from the "attachment-options.html"
    template.

    This page displays a grid of images that the user can select using
    checkboxes.
    """

    # A list of the filenames in the static/images directory.
    image_filenames = os.listdir(os.path.join(app.static_folder, "images"))

    # The image_list_form_builder method creates a form that displays a grid
    # of images, checkboxes, and captions with a Submit button. All images
    # passed in image_filenames will be shown, and the captions will be the
    # title-cased filenames.

    # The form must be built dynamically due to limitations in WTForms. The
    # image_list_form_builder method therefore also returns a list of
    # attribute names in the form, which will be used by the HTML template
    # to properly render the form.
    form, var_names = image_list_form_builder(image_filenames)

    # If the form was submitted, validate the input and create the attachments.
    if form.validate_on_submit():

        # Build a dictionary that maps image filenames to captions.
        # There will be one dictionary entry per selected item in the form.
        filename_caption_pairs = construct_filename_caption_dictionary_list(
            form)

        # Check that the user selected at least one image, then proceed to
        # make requests to the Classroom API.
        if len(filename_caption_pairs) > 0:
            return create_attachments(filename_caption_pairs)
        else:
            return flask.render_template(
                "create-attachment.html",
                message="You didn't select any images.",
                form=form,
                var_names=var_names)

    return flask.render_template(
        "attachment-options.html",
        message=("You've reached the attachment options page. "
                "Select one or more images and click 'Create Attachment'."),
        form=form,
        var_names=var_names,
    )

Thao tác này sẽ tạo ra trang "Tạo tệp đính kèm" giống như sau:

Ví dụ về thành phần hiển thị lựa chọn nội dung trên Python

Giáo viên có thể chọn nhiều hình ảnh. Tạo một tệp đính kèm cho mỗi hình ảnh mà giáo viên đã chọn trong phương thức create_attachments.

Vấn đề về yêu cầu tạo tệp đính kèm

Lúc này, bạn đã biết giáo viên muốn đính kèm nội dung nào, hãy gửi yêu cầu tới API Lớp học để tạo tệp đính kèm cho bài tập. Lưu trữ thông tin chi tiết về tệp đính kèm trong cơ sở dữ liệu sau khi nhận được phản hồi từ API Lớp học.

Để bắt đầu, hãy tải một bản sao của dịch vụ Lớp học:

Python

Trong ví dụ chúng tôi cung cấp, phần phụ thuộc nằm trong tệp webapp/attachment_routes.py.

def create_attachments(filename_caption_pairs):
    """
    Create attachments and show an acknowledgement page.

    Args:
        filename_caption_pairs: A dictionary that maps image filenames to
            captions.
    """
    # Get the Google Classroom service.
    # We need to request the Classroom API from a specific URL while add-ons
    # are in Early Access.

    # A Google API Key can be created in your Google Cloud project's Credentials
    # settings: https://console.cloud.google.com/apis/credentials.
    # Click "Create Credentials" at top and choose "API key", then provide
    # the key in the discoveryServiceUrl below.
    classroom_service = googleapiclient.discovery.build(
        serviceName="classroom",
        version="v1",
        discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=ADD_ONS_ALPHA&key={GOOGLE_API_KEY}",
        credentials=credentials)

Gửi yêu cầu CREATE đến điểm cuối courses.courseWork.addOnAttachments. Đối với mỗi hình ảnh do giáo viên chọn, trước tiên hãy tạo một đối tượng AddOnAttachment:

Python

Trong ví dụ đã cung cấp, đây là phần tiếp theo của phương thức create_attachments.

# Create a new attachment for each image that was selected.
attachment_count = 0
for key, value in filename_caption_pairs.items():
    attachment_count += 1

    # Create a dictionary with values for the AddOnAttachment object fields.
    attachment = {
        # Specifies the route for a teacher user.
        "teacherViewUri": {
            "uri":
                flask.url_for(
                    "load_content_attachment", _scheme='https', _external=True),
        },
        # Specifies the route for a student user.
        "studentViewUri": {
            "uri":
                flask.url_for(
                    "load_content_attachment", _scheme='https', _external=True)
        },
        # The title of the attachment.
        "title": f"Attachment {attachment_count}",
    }

Bạn phải cung cấp ít nhất các trường teacherViewUri, studentViewUrititle cho mỗi tệp đính kèm. teacherViewUristudentViewUri đại diện cho các URL được tải khi tệp đính kèm được mở theo loại người dùng tương ứng.

Gửi đối tượng AddOnAttachment trong phần nội dung của yêu cầu đến điểm cuối addOnAttachments thích hợp. Cung cấp các giá trị nhận dạng courseId, itemId, itemTypeaddOnToken cho từng yêu cầu.

Python

Trong ví dụ đã cung cấp, đây là phần tiếp theo của phương thức create_attachments.

# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
    case "announcements":
        parent = classroom_service.courses().announcements()
    case "courseWorkMaterials":
        parent = classroom_service.courses().courseWorkMaterials()
    case _:
        parent = classroom_service.courses().courseWork()

# Issue a request to create the attachment.
resp = parent.addOnAttachments().create(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"],
    addOnToken=flask.session["addOnToken"],
    body=attachment).execute()

Tạo một mục cho tệp đính kèm này trong cơ sở dữ liệu cục bộ để sau này bạn có thể tải đúng nội dung. Lớp học sẽ trả về một giá trị id duy nhất trong phản hồi cho yêu cầu tạo, vì vậy, hãy dùng giá trị này làm khoá chính trong cơ sở dữ liệu của chúng ta. Ngoài ra, xin lưu ý rằng Lớp học sẽ truyền tham số truy vấn attachmentId khi mở Chế độ xem của giáo viên và học viên:

Python

Trong ví dụ đã cung cấp, đây là phần tiếp theo của phương thức create_attachments.

# Store the value by id.
new_attachment = Attachment(
    # The new attachment's unique ID, returned in the CREATE response.
    attachment_id=resp.get("id"),
    image_filename=key,
    image_caption=value)
db.session.add(new_attachment)
db.session.commit()

Vào thời điểm này, hãy cân nhắc định tuyến người dùng đến trang xác nhận để xác nhận rằng họ đã tạo thành công tệp đính kèm.

Cho phép tệp đính kèm từ tiện ích bổ sung của bạn

Giờ là thời điểm thích hợp để thêm mọi địa chỉ thích hợp vào trường Tiền tố URI đính kèm được phép trong trang Cấu hình ứng dụng SDK GWM. Tiện ích bổ sung của bạn chỉ có thể tạo tệp đính kèm từ một trong các tiền tố URI được liệt kê trên trang này. Đây là một biện pháp bảo mật giúp giảm khả năng xảy ra các cuộc tấn công xen giữa.

Cách đơn giản nhất là cung cấp miền cấp cao nhất trong trường này, ví dụ: https://example.com. https://localhost:<your port number>/ sẽ hoạt động nếu bạn đang sử dụng máy cục bộ làm máy chủ web.

Thêm tuyến cho Chế độ xem của giáo viên và học viên

Có 4 iframe trong đó tiện ích bổ sung của Google Lớp học có thể được tải. Cho đến nay, bạn chỉ đã tạo các tuyến phân phát iframe Chế độ xem khám phá tệp đính kèm. Tiếp theo, hãy thêm các tuyến để phân phát cả iframe Chế độ xem của giáo viên và học viên.

Bạn cần có iframe Chế độ xem dành cho giáo viên để hiển thị bản xem trước trải nghiệm của học viên. Tuy nhiên, bạn có thể cung cấp thêm thông tin hoặc các tính năng chỉnh sửa (không bắt buộc).

Chế độ xem của học viên là trang mà mỗi học viên nhìn thấy khi họ mở một tệp đính kèm của tiện ích bổ sung.

Để phục vụ mục đích của bài tập này, hãy tạo một tuyến /load-content-attachment duy nhất phân phát cả Chế độ xem cho giáo viên và học viên. Sử dụng các phương thức API Lớp học để xác định xem người dùng là giáo viên hay học viên khi trang tải.

Python

Trong ví dụ chúng tôi cung cấp, phần phụ thuộc nằm trong tệp webapp/attachment_routes.py.

@app.route("/load-content-attachment")
def load_content_attachment():
    """
    Load the attachment for the user's role."""

    # Since this is a landing page for the Teacher and Student View iframes, we
    # need to preserve the incoming query parameters.
    if flask.request.args.get("itemId"):
        flask.session["itemId"] = flask.request.args.get("itemId")
    if flask.request.args.get("itemType"):
        flask.session["itemType"] = flask.request.args.get("itemType")
    if flask.request.args.get("courseId"):
        flask.session["courseId"] = flask.request.args.get("courseId")
    if flask.request.args.get("attachmentId"):
        flask.session["attachmentId"] = flask.request.args.get("attachmentId")

Hãy lưu ý rằng bạn cũng nên xác thực người dùng tại thời điểm này. Bạn cũng nên xử lý các tham số truy vấn login_hinthd tại đây, đồng thời định tuyến người dùng đến quy trình uỷ quyền của bạn nếu cần. Xem thông tin chi tiết về hướng dẫn đăng nhập đã thảo luận trong các hướng dẫn từng bước trước đó để biết thêm thông tin về quy trình này.

Sau đó, hãy gửi yêu cầu đến điểm cuối getAddOnContext khớp với loại mục.

Python

Trong ví dụ đã cung cấp, đây là phần tiếp theo của phương thức load_content_attachment.

# Create an instance of the Classroom service.
classroom_service = googleapiclient.discovery.build(
    serviceName="classroom"
    version="v1",
    discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=ADD_ONS_ALPHA&key={GOOGLE_API_KEY}",
    credentials=credentials)

# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
    case "announcements":
        parent = classroom_service.courses().announcements()
    case "courseWorkMaterials":
        parent = classroom_service.courses().courseWorkMaterials()
    case _:
        parent = classroom_service.courses().courseWork()

addon_context_response = parent.getAddOnContext(
    courseId=flask.session["courseId"],
    itemId=flask.session["itemId"]).execute()

Phương thức này trả về thông tin về vai trò của người dùng hiện tại trong lớp. Thay đổi chế độ xem mà người dùng nhìn thấy tuỳ thuộc vào vai trò của họ. Chính xác một trong các trường studentContext hoặc teacherContext được điền sẵn vào đối tượng phản hồi. Kiểm tra những vấn đề đó để xác định cách ứng phó với người dùng.

Trong mọi trường hợp, hãy sử dụng giá trị tham số truy vấn attachmentId để biết cần truy xuất tệp đính kèm nào từ cơ sở dữ liệu của chúng tôi. Tham số truy vấn này được cung cấp khi mở URI Khung hiển thị của giáo viên hoặc học viên.

Python

Trong ví dụ đã cung cấp, đây là phần tiếp theo của phương thức load_content_attachment.

# Determine which view we are in by testing the returned context type.
user_context = "student" if addon_context_response.get(
    "studentContext") else "teacher"

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

# Set the text for the next page depending on the user's role.
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 enjoy this image of a famous landmark!")

# Show the content with the customized message text.
return flask.render_template(
    "show-content-attachment.html",
    message=message_str,
    image_filename=attachment.image_filename,
    image_caption=attachment.image_caption,
    responses=response_strings)

Kiểm thử tiện ích bổ sung

Hãy hoàn thành các bước sau để kiểm thử quá trình tạo tệp đính kèm:

  • Đăng nhập vào [Google Lớp học] với tư cách là một trong những người dùng kiểm thử Giáo viên.
  • Chuyển đến thẻ Bài tập trên lớp rồi tạo một Bài tập mới.
  • Nhấp vào nút Tiện ích bổ sung bên dưới vùng văn bản rồi chọn tiện ích bổ sung của bạn. Iframe sẽ mở ra và tiện ích bổ sung sẽ tải URI thiết lập tệp đính kèm mà bạn đã chỉ định trên trang Cấu hình ứng dụng của SDK GWM.
  • Chọn một phần nội dung để đính kèm vào bài tập.
  • Đóng iframe sau khi quy trình tạo tệp đính kèm hoàn tất.

Bạn sẽ thấy một thẻ tệp đính kèm xuất hiện trong giao diện người dùng tạo bài tập trong Google Lớp học. Nhấp vào thẻ để mở iframe Chế độ xem của giáo viên và xác nhận rằng đúng tệp đính kèm đã xuất hiện. Nhấp vào nút Giao.

Hãy hoàn thành các bước sau để kiểm tra trải nghiệm của học viên:

  • Sau đó, đăng nhập vào Lớp học với tư cách là người dùng thử nghiệm học viên trong cùng lớp với người dùng thử nghiệm là giáo viên.
  • Tìm bài tập kiểm tra trong thẻ Bài tập trên lớp.
  • Mở rộng bài tập rồi nhấp vào thẻ tệp đính kèm để mở iframe Chế độ xem của học viên.

Kiểm tra để đảm bảo học viên đã đính kèm đúng tệp.

Xin chúc mừng! Bạn đã sẵn sàng để chuyển sang bước tiếp theo: tạo tệp đính kèm thuộc loại hoạt động.