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

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

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

خلال هذه الجولة الإرشادية، عليك إكمال ما يلي:

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

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

تفعيل واجهة برمجة التطبيقات Classroom API

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

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

كما سبق أن ناقشنا، تُرسِل Google Classroom مَعلمات طلبات البحث عندتحميل "عرض استكشاف المرفقات" في إطار iframe:

  • courseId: رقم تعريف الدورة التدريبية الحالية في Classroom.
  • itemId: معرّف فريد لمادة CourseWork أو CourseWorkMaterial أو Announcement التي تتلقّى مرفق الإضافة.
  • itemType: إما "courseWork" أو "courseWorkMaterials" أو "announcement".
  • 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 الجديدة. ننصحك بإنشاء صفحة جديدة لأغراض هذا التمرين حتى تحافظ على سلوك تسجيل الدخول المُوحَّد الذي تم تنفيذه في خطوة الشرح الثانية، مثل إبطال أذونات التطبيق. من المفترض أن تكون هذه الأدوات مفيدة عند إنشاء الإضافة واختبارها.

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

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

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

السماح بالمرفقات من إضافتك

الآن هو الوقت المناسب لإضافة أي عناوين مناسبة إلى حقل "بادئات عناوين URL" في حقل "المرفقات المسموح بها" في صفحة إعدادات التطبيق لحزمة تطوير البرامج (SDK) في Google Workspace Marketplace. لا يمكن لإضافة إنشاء مرفقات إلا من إحدى بادئات معرّفات الموارد المنتظمة المدرَجة في هذه الصفحة. هذا إجراء أمني للمساعدة في تقليل احتمالية هجمات الوسيط.

إنّ أبسط طريقة هي تقديم نطاقك من المستوى الأعلى في هذا الحقل، على سبيل المثال https://example.com. https://localhost:<your port number>/ لن يعمل إذا كنت تستخدم جهازك المحلي لخادم الويب.

إضافة مسارات لعرض "المعلّم" و"الطالب"

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

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

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

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

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",
    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 وتحميل الإضافة عنوان URL لإعداد المرفق الذي تحديدته في صفحة إعداد التطبيق لحزمة تطوير البرامج (SDK) في Google Workspace Marketplace.
  • اختَر قطعة محتوى لإرفاقها بالمهمة.
  • أغلِق إطار iframe بعد اكتمال عملية إنشاء المرفق.

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

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

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

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

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