קבצים מצורפים מסוג תוכן

זוהי ההדרכה המפורטת הרביעית בסדרת ההדרכה בנושא תוספים ל-Classroom.

בהדרכה המפורטת הזו משתמשים ב-Google Classroom API כדי ליצור קבצים מצורפים. אתם מספקים למשתמשים מסלולים לצפייה בתוכן של הקבצים המצורפים. הצפיות משתנות בהתאם לתפקיד של המשתמש בכיתה. ההדרכה המפורטת הזו עוסקת בקבצים מצורפים מסוג תוכן שלא מחייבים הגשה של תלמיד.

ההדרכה המפורטת כוללת את הדברים הבאים:

  • מאחזרים את הפרמטרים הבאים של שאילתות התוספים ומשתמשים בהם:
    • addOnToken: אסימון הרשאה שמועבר לתצוגת גילוי הקבצים המצורפים.
    • itemId: מזהה ייחודי של ה-CourseWork, CourseWorkMaterial או ההודעה של התוסף, שמקבלים את הקובץ המצורף.
    • itemType: "courseWork", "courseWorkMaterials" או "announc החל".
    • courseId: מזהה ייחודי של הקורס ב-Google Classroom שבו נוצרת המטלה.
    • attachmentId: מזהה ייחודי שמערכת Google Classroom מקצה לקובץ מצורף של תוסף אחרי שיוצרים אותו.
  • הטמעת אחסון מתמיד לקבצים מצורפים מסוג תוכן.
  • מתן מסלולים ליצירת קבצים מצורפים ולהצגת מסגרות iframe בתצוגה למורים ובתצוגה לתלמידים.
  • לשלוח את הבקשות הבאות ל-API של התוספים ב-Google Classroom:
    • יצירת קובץ מצורף חדש.
    • מקבלים את ההקשר של התוסף, שמזהה אם המשתמש שמחובר לחשבון הוא תלמיד או מורה.

אחרי שמסיימים, אפשר להתחבר כמורים וליצור קבצים מצורפים מסוג תוכן של מטלות. המורים והתלמידים בכיתה יכולים גם לצפות בתוכן.

הפעלה של Classroom API

צריך לבצע קריאות ל-Classroom API החל מהשלב הזה. כדי לבצע קריאות לפרויקט ב-Google Cloud, צריך להפעיל את ה-API. עוברים לרשומה בספרייה של Google Classroom API ובוחרים באפשרות Enable.

טיפול בפרמטרים של השאילתה בתצוגת גילוי הקבצים המצורפים

כפי שהסברנו קודם, מערכת Google Classroom מעבירה פרמטרים של שאילתה כשטוענים את תצוגת Discovery של הקבצים המצורפים ב-iframe:

  • courseId: המזהה של הקורס הנוכחי ב-Classroom.
  • itemId: מזהה ייחודי של ה-CourseWork, CourseWorkMaterial או ההודעה של התוסף, שמקבלים את הקובץ המצורף.
  • itemType: "courseWork", "courseWorkMaterials" או "announc החל".
  • addOnToken: אסימון שמשמש לאישור פעולות מסוימות של תוספים ל-Classroom.
  • login_hint: מזהה Google של המשתמש הנוכחי.

ההדרכה המפורטת הזו עובדת על courseId, itemId, itemType וגם addOnToken. לשמור ולהעביר אותן בזמן ביצוע קריאות ל-Classroom API.

כמו בשלב הקודם בהדרכה המפורטת, שומרים בסשן את ערכי הפרמטרים של השאילתה שמעבירים. חשוב לעשות זאת כשפותחים את התצוגה של גילוי הקבצים המצורפים, כי זו ההזדמנות היחידה של Classroom להעביר את הפרמטרים של השאילתה.

Python

מנווטים לקובץ של שרת Flask שמספק מסלולים לתצוגת Discovery של הקבצים המצורפים (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")

כותבים את הערכים האלה בסשן רק אם הם קיימים. הם לא מועברים שוב אם המשתמש חוזר לתצוגת קבצים מצורפים מסוג Discovery מאוחר יותר בלי לסגור את ה-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 לנקודת הקצה (endpoint) 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()

בשלב הזה, כדאי לנתב את המשתמש לדף אישור, כדי לאשר שהוא יצר קבצים מצורפים בהצלחה.

אפשר לצרף קבצים מהתוסף

עכשיו הגיע הזמן להוסיף את הכתובות המתאימות לשדה 'הקידומות המותרות של קבצים מצורפים' בדף הגדרת האפליקציה של Google Workspace Marketplace. התוסף יכול ליצור קבצים מצורפים רק מאחת מקידומות ה-URI שמפורטות בדף הזה. זהו אמצעי אבטחה שעוזר לצמצם את הסיכוי להתקפות אדם בתווך.

הגישה הפשוטה ביותר היא לציין את הדומיין ברמה העליונה בשדה הזה, לדוגמה https://example.com. https://localhost:<your port number>/ יפעל אם משתמשים במכונה המקומית כשרת האינטרנט.

הוספת מסלולים לתצוגה של 'מורים' ושל 'תלמידים'

יש ארבעה רכיבי iframe שבהם ניתן לטעון תוסף של Google Classroom. כתוצאה מכך, יש לכם רק מסלולים שיוצרים את ה-iframe של תצוגת הגילוי של הקבצים המצורפים. בשלב הבא מוסיפים מסלולים כדי להציג גם את מסגרות ה-iframe של תצוגת המורים והתלמידים.

ה-iframe של תצוגת המורה נדרש כדי להציג תצוגה מקדימה של חוויית התלמידים, אבל יכול לכלול מידע נוסף או תכונות עריכה.

תצוגה לתלמידים היא הדף שמוצג לכל תלמיד שפותחים קובץ מצורף של תוסף.

לצורך התרגיל הזה, צריך ליצור נתיב אחד של /load-content-attachment שמשמש גם ל'תצוגה למורים' וגם ל'תצוגה לתלמידים'. אפשר להשתמש ב-methods של 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, ולנתב את המשתמש לתהליך ההרשאה במקרה הצורך. למידע נוסף על התהליך הזה, אפשר לעיין בפרטי ההנחיות להתחברות שצוינו בהדרכות מפורטות קודמות.

לאחר מכן שולחים בקשה לנקודת הקצה (endpoint) getAddOnContext שתואמת לסוג הפריט.

Python

בדוגמה שלנו, זה המשך של ה-method 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

בדוגמה שלנו, זה המשך של ה-method 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 להגדרת קובץ מצורף שציינתם בדף הגדרת האפליקציה ב-Google Workspace Marketplace SDK.
  • בוחרים קטע תוכן שיצורף למטלה.
  • סוגרים את ה-iframe בסיום תהליך יצירת הקובץ המצורף.

כרטיס מצורף אמור להופיע בממשק המשתמש ליצירת מטלה ב-Google Classroom. לוחצים על הכרטיס כדי לפתוח את ה-iframe של תצוגת המורים ולוודא שהקובץ המצורף הנכון מופיע. לוחצים על הלחצן הקצאה.

כך בודקים את חוויית התלמידים:

  • לאחר מכן נכנסים ל-Classroom כמשתמש של בחינת התלמידים באותה כיתה כמו משתמש הבדיקה של המורה.
  • מוצאים את המטלה בכרטיסייה 'עבודות'.
  • מרחיבים את המטלה ולוחצים על הכרטיס של הקובץ המצורף כדי לפתוח את ה-iframe של התצוגה לתלמידים.

מוודאים שהקובץ המצורף הנכון מופיע עבור התלמיד/ה.

כל הכבוד! אתם מוכנים להמשיך לשלב הבא: יצירת קבצים מצורפים מסוג פעילות.