مرفقات نوع المحتوى

هذه هي الجولة التفصيلية الرابعة في سلسلة الجولات التفصيلية حول إضافات Classroom.

في هذه الجولة التفصيلية، تتفاعل مع Google Classroom API لإنشاء مرفقات. ويمكنك توفير مسارات للمستخدمين لعرض محتوى المرفق. وتختلف طرق العرض تبعًا لدور المستخدم في الفئة. تتناول هذه الجولة التفصيلية مرفقات من نوع المحتوى لا تتطلّب أن يرسلها الطالب.

خلال هذه الجولة التفصيلية، يمكنك إكمال ما يلي:

  • استرداد مَعلمات طلب البحث الإضافية التالية واستخدامها:
    • addOnToken: تم تمرير رمز تفويض مميز إلى طريقة عرض "اكتشاف المرفقات".
    • itemId: معرّف فريد لـ CourseWork أو CourseWorkMaterial أو الإعلان الذي يتلقى مرفق الإضافة.
    • itemType: إما "courseWork" أو "courseWorkMaterials" أو "الإعلان"
    • courseId: معرّف فريد للدورة التدريبية في Google Classroom التي يتم إنشاء المهمة فيها.
    • attachmentId: هو معرّف فريد يعيّنه Google Classroom لمرفق إضافة بعد الإنشاء.
  • تنفيذ التخزين الدائم للمرفقات من نوع المحتوى.
  • يمكنك توفير مسارات لإنشاء المرفقات وعرض إطارات iframe المخصصة للمعلّمين وإطارات iframe في "مشاهدة الطلاب".
  • إرسال الطلبات التالية إلى واجهة برمجة تطبيقات إضافات Google Classroom:
    • إنشاء مرفق جديد
    • يمكنك الحصول على سياق الإضافة الذي يحدّد ما إذا كان المستخدم الذي سجّل الدخول طالبًا أو معلّمًا.

بعد الانتهاء، يمكنك إنشاء مرفقات من نوع المحتوى في المهام الدراسية من خلال واجهة مستخدم Google Classroom عند تسجيل الدخول كمعلّم. يمكن للمعلمين والطلاب في الفصل أيضًا عرض المحتوى.

تفعيل Classroom API

إجراء اتصالات باستخدام Classroom API بدءًا من هذه الخطوة. يجب تفعيل واجهة برمجة التطبيقات لمشروعك على Google Cloud قبل أن تتمكّن من إجراء مكالمات إليها. انتقِل إلى إدخال مكتبة Google Classroom API واختَر تفعيل.

التعامل مع مَعلمات طلب البحث لعرض استكشاف المرفقات

كما ذكرنا سابقًا، يعمل Google Classroom على تمرير معلَمات طلب البحث عند تحميل طريقة عرض استكشاف المرفقات في إطار iframe:

  • courseId: رقم تعريف الدورة التدريبية الحالية في Classroom.
  • itemId: معرّف فريد لـ CourseWork أو CourseWorkMaterial أو الإعلان الذي يتلقى مرفق الإضافة.
  • itemType: إما "courseWork" أو "courseWorkMaterials" أو "إعلان"
  • addOnToken: هو رمز مميّز يُستخدم لتفويض إجراءات معيّنة لإضافة Classroom.
  • login_hint: رقم تعريف Google للمستخدم الحالي

تتناول هذه الجولة التفصيلية courseId وitemId وitemType وaddOnToken. الاحتفاظ بهذه الرموز وتمريرها عند إصدار الطلبات في Classroom API.

وكما في الخطوة التفصيلية السابقة، خزِّن قيم مَعلمات طلب البحث التي تم تمريرها في جلستنا. من المهم إجراء ذلك عند فتح "عرض استكشاف المرفقات" لأول مرة، لأن هذه هي الفرصة الوحيدة المتاحة لـ Classroom لتمرير معلَمات طلب البحث هذه.

Python

انتقِل إلى ملف خادم 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: الشرح الذي سيتم عرضه مع الصورة

Python

توسيع تنفيذ SQLite وflask_sqlalchemy من الخطوات السابقة.

انتقِل إلى الملف الذي حدّدت جدول المستخدمين فيه (models.py إذا كنت تتابع المثال المقدَّم). أضف ما يلي في الجزء السفلي من الملف أسفل فئة 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))

قم باستيراد فئة المرفقات الجديدة إلى ملف الخادم الذي يحتوي على مسارات معالجة المرفقات.

إعداد مسارات جديدة

ابدأ هذه الجولة التفصيلية بإعداد بعض الصفحات الجديدة في تطبيقنا. وتتيح هذه الإضافات للمستخدم إنشاء المحتوى وعرضه من خلال إضافتنا.

إضافة مسارات إنشاء المرفقات

تحتاج إلى صفحات للمعلم لتحديد المحتوى وإصدار طلبات إنشاء المرفقات. نفِّذ مسار /attachment-options لعرض خيارات المحتوى ليختارها المعلّم. تحتاج أيضًا إلى قوالب لصفحات اختيار المحتوى وتأكيد الإنشاء. وتحتوي أمثلتنا المقدَّمة على نماذج لهذه العناصر، ويمكنها أيضًا عرض الطلبات والردود من Classroom API.

يمكنك بدلاً من ذلك تعديل الصفحة المقصودة الحالية لعرض استكشاف المرفقات لعرض خيارات المحتوى بدلاً من إنشاء صفحة /attachment-options الجديدة. نقترح عليك إنشاء صفحة جديدة لأغراض هذا التمرين كي تحافظ على سلوك خدمة الدخول المُوحَّد (SSO) الذي تم تنفيذه في الخطوة الثانية، مثل إبطال أذونات التطبيق. ومن المفترض أن تكون هذه مفيدة أثناء إنشاء الإضافة واختبارها.

يمكن للمعلم الاختيار من بين مجموعة صغيرة من الصور التي تتضمن ترجمة في المثال المقدم. لقد قدمنا أربع صور للمعالم الشهيرة التي يتم اشتقاق تسمياتها من أسماء الملفات.

Python

في المثال الذي قدمناه، ستجد ذلك في ملف 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,
    )

ينتج عن ذلك صفحة "إنشاء مرفقات" تشبه ما يلي:

مثال على عرض اختيار المحتوى في Python

يمكن للمعلّم اختيار عدة صور. أنشئ مرفقًا واحدًا لكل صورة يختارها المعلِّم في طريقة create_attachments.

مشاكل في طلبات إنشاء المرفقات

والآن بعد أن عرفت أجزاء المحتوى التي يرغب المعلّم في إرفاقها، يمكنك إصدار طلبات إلى Classroom API لإنشاء مرفقات على المهام الدراسية. قم بتخزين تفاصيل المرفق في قاعدة البيانات الخاصة بك بعد تلقي رد من Classroom API.

ابدأ بالحصول على مثيل لخدمة Classroom:

Python

في المثال الذي قدمناه، ستجد ذلك في ملف 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:

Python

في المثال الذي قدّمناه، هذه تكملة لطريقة 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 مع كل طلب.

Python

في المثال الذي قدّمناه، هذه تكملة لطريقة 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 يمرّر معلَمة طلب البحث attachmentId عند فتح طرق العرض الخاصة بالمعلّمين والطلاب:

Python

في المثال الذي قدّمناه، هذه تكملة لطريقة 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 لعرض المرفقات حتى الآن. بعد ذلك، أضف مسارات لخدمة إطارات iframe الخاصة بعرض المعلم والطلاب أيضًا.

يجب توفُّر إطار iframe لمشاهدة المعلّمين لعرض معاينة لتجربة الطالب، ولكن يمكن أن يتضمّن اختياريًا معلومات إضافية أو ميزات تعديل.

طريقة العرض للطلاب هي الصفحة التي يتم تقديمها لكل طالب عند فتح مرفق إضافة.

لأغراض هذا التمرين، أنشئ مسار /load-content-attachment واحدًا يخدم كلاً من طريقة عرض المعلم والطلاب. استخدِم طرق Classroom API لتحديد ما إذا كان المستخدم معلّمًا أو طالبًا عند تحميل الصفحة.

Python

في المثال الذي قدمناه، ستجد ذلك في ملف 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 التي تتطابق مع نوع العنصر.

Python

في المثال الذي قدّمناه، هذه مواصلة للطريقة 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()

تعرض هذه الطريقة معلومات حول دور المستخدم الحالي في الفئة. ويمكنك تغيير طريقة العرض المعروضة للمستخدم حسب دوره. تتم تعبئة حقل واحد بالضبط من الحقلين studentContext أو teacherContext في كائن الاستجابة. افحصها لتحديد كيفية التعامل مع المستخدم.

على أي حال، استخدِم قيمة معلَمة طلب البحث attachmentId لمعرفة المرفق الذي يجب استرداده من قاعدة البيانات. يتم توفير معلمة طلب البحث هذه عند فتح معرفات الموارد المنتظمة (URI) لعرض المعلم أو الطالب.

Python

في المثال الذي قدّمناه، هذه مواصلة للطريقة 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 Marketplace.
  • اختر جزءًا من المحتوى لإرفاقه بالمهمة.
  • يمكنك إغلاق إطار iframe بعد اكتمال عملية إنشاء المرفقات.

من المفترض أن تظهر لك بطاقة مرفق في واجهة مستخدم إنشاء المهام الدراسية في Google Classroom. انقر على البطاقة لفتح إطار iframe في "طريقة عرض المعلّمين" والتأكّد من ظهور المرفق الصحيح. انقر على الزر تعيين.

أكمِل الخطوات التالية لاختبار تجربة الطالب:

  • بعد ذلك، سجِّل الدخول إلى Classroom كمستخدم اختباري للطلاب في الصف نفسه الذي ينتمي إليه مستخدم اختبار المعلّم.
  • ابحث عن المهمة الدراسية في علامة التبويب "الواجب الدراسي".
  • وسِّع المهمة وانقر على بطاقة المرفق لفتح إطار iframe للعرض للطلاب.

تأكَّد من ظهور المرفق الصحيح للطالب.

تهانينا! يمكنك الآن المتابعة إلى الخطوة التالية: إنشاء مرفقات من نوع النشاط.