پیوست های نوع محتوا

این چهارمین راهنمای گام به گام از مجموعه راهنمای افزونه‌های Classroom است.

در این راهنما، شما با API کلاس درس گوگل برای ایجاد پیوست‌ها تعامل می‌کنید. شما مسیرهایی را برای کاربران فراهم می‌کنید تا محتوای پیوست را مشاهده کنند. نحوه نمایش بسته به نقش کاربر در کلاس متفاوت است. این راهنما، پیوست‌های از نوع محتوا را پوشش می‌دهد که نیازی به ارسال توسط دانشجو ندارند.

در طول این راهنمای گام به گام، موارد زیر را تکمیل می‌کنید:

  • پارامترهای پرس و جوی افزونه زیر را بازیابی و استفاده کنید:
    • addOnToken : یک توکن مجوز که به نمای کشف پیوست ارسال می‌شود.
    • itemId : یک شناسه منحصر به فرد برای CourseWork، CourseWorkMaterial یا Announcement که پیوست افزونه را دریافت می‌کند.
    • itemType : یا "courseWork"، "courseWorkMaterials" یا "announcement".
    • courseId : یک شناسه منحصر به فرد برای دوره Google Classroom که در آن تکلیف ایجاد می‌شود.
    • attachmentId : شناسه منحصر به فردی که توسط Google Classroom پس از ایجاد، به یک پیوست افزونه اختصاص داده می‌شود.
  • پیاده‌سازی فضای ذخیره‌سازی پایدار برای پیوست‌های از نوع محتوا.
  • مسیرهایی برای ایجاد پیوست‌ها و ارائه iframeهای نمای معلم و نمای دانش‌آموز ارائه دهید.
  • درخواست‌های زیر را به API افزونه‌های Google Classroom ارسال کنید:
    • یک پیوست جدید ایجاد کنید.
    • زمینه افزونه را دریافت کنید، که مشخص می‌کند کاربر وارد شده دانش‌آموز است یا معلم.

پس از اتمام کار، می‌توانید از طریق رابط کاربری Google Classroom و هنگام ورود به سیستم به عنوان معلم، پیوست‌های محتوایی برای تکالیف ایجاد کنید. معلمان و دانش‌آموزان کلاس نیز می‌توانند محتوا را مشاهده کنند.

فعال کردن API کلاس درس

با شروع از این مرحله، API کلاس درس را فراخوانی کنید. قبل از اینکه بتوانید آن را فراخوانی کنید، API باید برای پروژه Google Cloud شما فعال شود. به ورودی کتابخانه API کلاس درس Google بروید و Enable را انتخاب کنید.

پارامترهای کوئری مربوط به نمای کشف پیوست (Attachment Discovery View) را مدیریت کنید.

همانطور که قبلاً بحث شد ، Google Classroom هنگام بارگذاری نمای کشف پیوست در iframe، پارامترهای پرس و جو را ارسال می‌کند:

  • courseId : شناسه‌ی دوره‌ی فعلی Classroom.
  • itemId : یک شناسه منحصر به فرد برای CourseWork، CourseWorkMaterial یا Announcement که پیوست افزونه را دریافت می‌کند.
  • itemType : یا "courseWork"، "courseWorkMaterials" یا "announcement".
  • addOnToken : توکنی که برای مجاز کردن برخی از اقدامات افزونه Classroom استفاده می‌شود.
  • login_hint : شناسه گوگل کاربر فعلی.

این راهنما به courseId ، itemId ، itemType و addOnToken می‌پردازد. این موارد را هنگام فراخوانی Classroom API حفظ و ارسال کنید.

همانند مرحله قبل، مقادیر پارامترهای کوئری ارسالی را در سشن خود ذخیره کنید. مهم است که این کار را هنگام باز شدن نمای کشف پیوست انجام دهیم، زیرا این تنها فرصت Classroom برای ارسال این پارامترهای کوئری است.

پایتون

به فایل سرور Flask خود که مسیرهایی برای نمای کشف پیوست ( attachment-discovery-routes.py اگر از مثال ارائه شده ما پیروی می‌کنید) ارائه می‌دهد، بروید. در بالای مسیر ورود افزونه خود ( /classroom-addon در مثال ارائه شده ما)، پارامترهای کوئری courseId ، itemId ، itemType و addOnToken را بازیابی و ذخیره کنید.

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

این مقادیر را فقط در صورتی که وجود داشته باشند در جلسه بنویسید؛ اگر کاربر بعداً بدون بستن iframe به نمای کشف پیوست‌ها بازگردد، دوباره ارسال نمی‌شوند.

افزودن فضای ذخیره‌سازی پایدار برای پیوست‌های نوع محتوا

شما به یک رکورد محلی از هرگونه پیوست ایجاد شده نیاز دارید. این به شما امکان می‌دهد محتوایی را که معلم انتخاب کرده است با استفاده از شناسه‌های ارائه شده توسط Classroom جستجو کنید.

یک طرح پایگاه داده برای یک Attachment تنظیم کنید. مثال ارائه شده ما پیوست‌هایی را نشان می‌دهد که یک تصویر و یک عنوان را نشان می‌دهند. یک Attachment شامل ویژگی‌های زیر است:

  • attachment_id : یک شناسه منحصر به فرد برای یک پیوست. توسط Classroom اختصاص داده شده و هنگام ایجاد پیوست در پاسخ بازگردانده می‌شود.
  • image_filename : نام فایل محلی تصویری که قرار است نمایش داده شود.
  • image_caption : عنوانی که قرار است همراه تصویر نمایش داده شود.

پایتون

پیاده‌سازی SQLite و flask_sqlalchemy را از مراحل قبلی گسترش دهید.

به فایلی که جدول کاربر (User Table) خود را در آن تعریف کرده‌اید بروید (اگر از مثال ما پیروی می‌کنید، models.py ). کد زیر را در انتهای فایل، زیر کلاس User Class) اضافه کنید.

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

کلاس Attachment جدید را به همراه مسیرهای مدیریت پیوست خود در فایل سرور وارد کنید.

مسیرهای جدید را تنظیم کنید

این مرحله از راهنما را با تنظیم چند صفحه جدید در برنامه‌مان آغاز می‌کنیم. این صفحات به کاربر اجازه می‌دهند از طریق افزونه ما محتوا ایجاد و مشاهده کند.

اضافه کردن مسیرهای ایجاد پیوست

شما به صفحاتی نیاز دارید که معلم بتواند محتوا را انتخاب کند و درخواست‌های ایجاد پیوست را صادر کند. مسیر /attachment-options را برای نمایش گزینه‌های محتوا برای انتخاب معلم پیاده‌سازی کنید. همچنین به قالب‌هایی برای صفحات انتخاب محتوا و تأیید ایجاد نیاز دارید. مثال‌های ارائه شده ما شامل قالب‌هایی برای این موارد هستند و همچنین می‌توانند درخواست‌ها و پاسخ‌ها را از Classroom API نمایش دهند.

توجه داشته باشید که می‌توانید به جای ایجاد صفحه جدید /attachment-options ، صفحه فرود موجود در نمای کشف پیوست خود را برای نمایش گزینه‌های محتوا تغییر دهید. توصیه می‌کنیم برای اهداف این تمرین، یک صفحه جدید ایجاد کنید تا رفتار SSO پیاده‌سازی شده در مرحله دوم ، مانند لغو مجوزهای برنامه، حفظ شود. این موارد باید هنگام ساخت و آزمایش افزونه شما مفید باشند.

یک معلم می‌تواند از میان مجموعه کوچکی از تصاویر دارای زیرنویس در مثال ارائه شده ما، تصویر مورد نظر خود را انتخاب کند. ما چهار تصویر از مکان‌های دیدنی معروف ارائه داده‌ایم که زیرنویس‌های آنها از نام فایل‌ها گرفته شده است.

پایتون

در مثال ارائه شده ما، این در فایل 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,
    )

این یک صفحه "ایجاد پیوست‌ها" ایجاد می‌کند که شبیه به صفحه زیر است:

نمای انتخاب محتوا به عنوان مثال پایتون

معلم می‌تواند چندین تصویر را انتخاب کند. برای هر تصویری که معلم در متد create_attachments انتخاب کرده است، یک پیوست ایجاد کنید.

درخواست‌های ایجاد پیوست را صادر کنید

حالا که می‌دانید معلم می‌خواهد کدام بخش از محتوا را پیوست کند، درخواست‌هایی را به Classroom API ارسال کنید تا در تکلیف ما پیوست ایجاد شود. پس از دریافت پاسخ از Classroom API، جزئیات پیوست را در پایگاه داده خود ذخیره کنید.

با دریافت یک نمونه از سرویس Classroom شروع کنید:

پایتون

در مثال ارائه شده ما، این در فایل 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.
    classroom_service = googleapiclient.discovery.build(
        serviceName="classroom",
        version="v1",
        credentials=credentials)

یک درخواست CREATE به نقطه پایانی courses.courseWork.addOnAttachments ارسال کنید. برای هر تصویر انتخاب شده توسط معلم، ابتدا یک شیء AddOnAttachment بسازید:

پایتون

در مثال ارائه شده ما، این ادامه متد 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}",
    }

حداقل فیلدهای teacherViewUri ، studentViewUri و title باید برای هر پیوست ارائه شوند. teacherViewUri و studentViewUri نشان دهنده URLهایی هستند که هنگام باز شدن پیوست توسط نوع کاربر مربوطه بارگیری می‌شوند.

شیء AddOnAttachment را در بدنه‌ی درخواست به نقطه‌ی پایانی addOnAttachments مربوطه ارسال کنید. شناسه‌های courseId ، itemId ، itemType و addOnToken را به همراه هر درخواست ارائه دهید.

پایتون

در مثال ارائه شده ما، این ادامه متد 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()

یک ورودی برای این پیوست در پایگاه داده محلی خود ایجاد کنید تا بعداً بتوانید محتوای صحیح را بارگذاری کنید. Classroom در پاسخ به درخواست ایجاد، یک مقدار id منحصر به فرد برمی‌گرداند، بنابراین از این به عنوان کلید اصلی در پایگاه داده خود استفاده کنید. همچنین توجه داشته باشید که Classroom هنگام باز کردن نماهای Teacher و Student، پارامتر کوئری attachmentId را ارسال می‌کند:

پایتون

در مثال ارائه شده ما، این ادامه متد 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()

در این مرحله، کاربر را به یک صفحه تأیید هدایت کنید و تأیید کنید که با موفقیت پیوست‌ها را ایجاد کرده است.

اجازه دادن به پیوست‌ها از افزونه‌تان

اکنون زمان مناسبی است که آدرس‌های مناسب را به فیلد «پیشوندهای مجاز URI پیوست» در صفحه پیکربندی برنامه Google Workspace Marketplace SDK اضافه کنید. افزونه شما فقط می‌تواند از یکی از پیشوندهای URI ذکر شده در این صفحه پیوست ایجاد کند. این یک اقدام امنیتی برای کمک به کاهش احتمال حملات مرد میانی است.

ساده‌ترین روش این است که دامنه سطح بالای خود را در این فیلد ارائه دهید، برای مثال https://example.com . اگر از دستگاه محلی خود به عنوان وب سرور استفاده می‌کنید، https://localhost:<your port number>/ کار خواهد کرد.

اضافه کردن مسیرها برای نماهای معلم و دانش‌آموز

چهار iframe وجود دارد که افزونه‌ی Google Classroom می‌تواند در آن‌ها بارگذاری شود. تا اینجا فقط مسیرهایی ساخته‌اید که به iframe نمای Attachment Discovery View سرویس می‌دهند. در مرحله‌ی بعد، مسیرهایی را اضافه کنید که به iframeهای نمای معلم و دانش‌آموز نیز سرویس دهند.

آی‌فریم نمای معلم برای نمایش پیش‌نمایشی از تجربه دانش‌آموز لازم است، اما می‌تواند به صورت اختیاری شامل اطلاعات اضافی یا ویژگی‌های ویرایشی نیز باشد.

نمای دانشجو ، صفحه‌ای است که هنگام باز کردن یک پیوست افزونه، به هر دانشجو نمایش داده می‌شود.

برای اهداف این تمرین، یک مسیر /load-content-attachment ایجاد کنید که هم به نمای معلم و هم به نمای دانش‌آموز سرویس دهد. از متدهای Classroom API برای تعیین اینکه کاربر هنگام بارگیری صفحه معلم است یا دانش‌آموز استفاده کنید.

پایتون

در مثال ارائه شده ما، این در فایل 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")

به خاطر داشته باشید که در این مرحله باید کاربر را احراز هویت کنید. همچنین باید پارامتر کوئری login_hint را در اینجا مدیریت کنید و در صورت لزوم کاربر را به جریان احراز هویت خود هدایت کنید. برای اطلاعات بیشتر در مورد این جریان، به جزئیات راهنمای ورود که در مراحل قبلی بحث شده است، مراجعه کنید.

سپس یک درخواست به نقطه پایانی getAddOnContext ارسال کنید که با نوع آیتم مطابقت داشته باشد.

پایتون

در مثال ارائه شده ما، این ادامه متد load_content_attachment است.

# Create an instance of the Classroom service.
classroom_service = googleapiclient.discovery.build(
    serviceName="classroom"
    version="v1",
    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()

این متد اطلاعاتی در مورد نقش کاربر فعلی در کلاس برمی‌گرداند. نمای ارائه شده به کاربر را بسته به نقش او تغییر می‌دهد. دقیقاً یکی از فیلدهای studentContext یا teacherContext در شیء پاسخ پر شده است. این موارد را بررسی کنید تا نحوه‌ی آدرس‌دهی به کاربر را تعیین کنید.

در هر صورت، از مقدار پارامتر کوئری attachmentId برای دانستن اینکه کدام پیوست را از پایگاه داده خود بازیابی کنیم، استفاده کنید. این پارامتر کوئری هنگام باز کردن URI های نمای معلم یا دانش آموز ارائه می‌شود.

پایتون

در مثال ارائه شده ما، این ادامه متد 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)

افزونه را تست کنید

برای آزمایش ایجاد پیوست، مراحل زیر را انجام دهید:

  • به عنوان یکی از کاربران آزمون معلم خود، وارد [Google Classroom] شوید.
  • به برگه «کار کلاسی» بروید و یک تکلیف جدید ایجاد کنید.
  • روی دکمه افزونه‌ها در زیر قسمت متن کلیک کنید، سپس افزونه خود را انتخاب کنید. iframe باز می‌شود و افزونه ، URI تنظیمات پیوست را که در صفحه پیکربندی برنامه SDK بازار Google Workspace مشخص کرده‌اید، بارگذاری می‌کند.
  • یک قطعه محتوا را برای پیوست کردن به تکلیف انتخاب کنید.
  • پس از اتمام فرآیند ایجاد پیوست، iframe را ببندید.

شما باید یک کارت پیوست در رابط کاربری ایجاد تکلیف در گوگل کلاس روم (Google Classroom) ظاهر شود. روی کارت کلیک کنید تا iframe نمای معلم (Teacher View) باز شود و تأیید کنید که پیوست صحیح ظاهر می‌شود. روی دکمه اختصاص (Assign) کلیک کنید.

برای بررسی تجربه دانش‌آموز، مراحل زیر را انجام دهید:

  • سپس به عنوان کاربر آزمون دانش‌آموز در همان کلاسی که کاربر آزمون معلم در آن قرار دارد، وارد کلاس درس شوید.
  • تکلیف آزمون را در برگه «کار کلاسی» پیدا کنید.
  • تکلیف را باز کنید و روی کارت پیوست کلیک کنید تا iframe نمای دانش‌آموز باز شود.

تأیید کنید که پیوست صحیح برای دانش‌آموز نمایش داده شده است.

تبریک! شما آماده‌اید تا به مرحله بعدی بروید: ایجاد پیوست‌های از نوع فعالیت .