יצירת תוסף ל-Classroom

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

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

במהלך ההסבר המפורט הזה תבצעו את הפעולות הבאות:

  • יוצרים פרויקט חדש ב-Google Cloud עבור התוסף.
  • יוצרים אפליקציית אינטרנט בסיסית עם לחצני כניסה למקום.
  • פרסום דף מוצר של התוסף ב-Google Workspace Marketplace.

אחרי שמסיימים, אפשר להתקין את התוסף ולטעון אותו ב-iframe של תוספי Classroom.

דרישות מוקדמות

בוחרים שפה כדי לראות את הדרישות המוקדמות המתאימות:

Python

בדוגמה שלנו ב-Python נעשה שימוש ב-framework של Flask. בדף הסקירה הכללית אפשר להוריד את קוד המקור המלא של כל ההדרכות. הקוד של ההדרכה הספציפית הזו נמצא בספרייה /flask/01-basic-app/.

אם צריך, מתקינים Python 3.7 ואילך ומוודאים ש-pip זמין.

python -m ensurepip --upgrade

מומלץ גם להגדיר ולהפעיל סביבה וירטואלית חדשה של Python.

python3 -m venv .classroom-addon-env
source .classroom-addon-env/bin/activate

כל ספריית משנה של הדרכה בדוגמאות שהורדתם מכילה קובץ requirements.txt. אפשר להתקין במהירות את הספריות הנדרשות באמצעות pip. כדי להתקין את הספריות הנדרשות למדריך הזה, משתמשים בפקודה הבאה.

cd flask/01-basic-app
pip install -r requirements.txt

Node.js

בדוגמה שלנו ל-Node.js אנחנו משתמשים ב-framework‏ Express. אפשר להוריד את קוד המקור המלא של כל ההדרכות מדף הסקירה הכללית.

אם צריך, מתקינים את NodeJS בגרסה 16.13 ואילך.

מתקינים את מודולי הצומת הנדרשים באמצעות npm.

npm install

Java

בדוגמה שלנו ל-Java נעשה שימוש ב-Spring Boot framework. בדף הסקירה הכללית אפשר להוריד את קוד המקור המלא של כל המדריכים.

אם Java 11+‎ עדיין לא מותקנת במחשב, מתקינים אותה.

אפליקציות Spring Boot יכולות להשתמש ב-Gradle או ב-Maven כדי לטפל בבנייה ולנהל תלות. הדוגמה הזו כוללת את Maven wrapper, שדואג לבנייה מוצלחת בלי שתצטרכו להתקין את Maven עצמו.

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

java --version
./mvnw --version

או ב-Windows:

java -version
mvnw.cmd --version

הגדרת פרויקט ב-Google Cloud

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

יצירת הפרויקט

כדי ליצור פרויקט חדש ב-Google Cloud, עוברים אל הדף ליצירת פרויקט. אתם יכולים לתת לפרויקט החדש כל שם שתרצו. לוחצים על יצירה.

יצירת הפרויקט החדש נמשכת כמה רגעים. אחרי שמסיימים, חשוב לבחור את הפרויקט. אפשר לבחור אותו בתפריט הנפתח של בורר הפרויקטים בראש המסך, או ללחוץ על SELECT PROJECT בתפריט ההתראות בפינה השמאלית העליונה.

בוחרים את הפרויקט ב-Google Cloud Console.

צירוף ה-SDK של Google Workspace Marketplace לפרויקט ב-Google Cloud

עוברים לדפדפן API Library. חיפוש של Google Workspace Marketplace SDK. ה-SDK אמור להופיע ברשימת התוצאות.

כרטיס Google Workspace Marketplace SDK

בוחרים בכרטיס Google Workspace Marketplace SDK ולוחצים על הפעלה.

הגדרת Google Workspace Marketplace SDK

ב-Google Workspace Marketplace מוצג דף המוצר שדרכו משתמשים ואדמינים מתקינים את התוסף. כדי להמשיך, צריך להגדיר את הגדרת האפליקציה, את הכרטיס בחנות ואת מסך ההסכמה של OAuth ב-Marketplace SDK.

הגדרת אפליקציה

עוברים לדף App Configuration (הגדרת האפליקציה) ב-Marketplace SDK. עליך לספק את הפרטים הבאים:

  • מגדירים את ניראות האפליקציה לערך Public או Private.

    • ההגדרה 'ציבורית' מיועדת לאפליקציות שבסופו של דבר יופצו למשתמשי קצה. אפליקציה ציבורית צריכה לעבור תהליך אישור לפני שהיא מתפרסמת למשתמשי קצה, אבל אתם יכולים לציין משתמשים שיכולים להתקין אותה ולבדוק אותה כטיוטה. זהו מצב לפני פרסום, שיאפשר לכם לבדוק ולפתח את התוסף לפני שתשלחו אותו לאישור.
    • ההגדרה 'פרטי' מתאימה לבדיקות פנימיות ולפיתוח. רק משתמשים באותו דומיין שבו נוצר הפרויקט יכולים להתקין אפליקציה פרטית. לכן, צריך להגדיר את סטטוס החשיפה כפרטי רק אם הפרויקט נוצר בדומיין עם מינוי ל-Google Workspace for Education. אחרת, משתמשי הבדיקה לא יוכלו להפעיל תוספים ל-Classroom.
  • אם רוצים להגביל את ההתקנה לאדמינים של הדומיין, מגדירים את הגדרות ההתקנה לערך Admin Only install.

  • בקטע App Integration (שילוב אפליקציות), בוחרים באפשרות Classroom add-on (תוסף ל-Classroom). מוצגת בקשה להזין את ה-URI של הגדרת הקובץ המצורף מאובטח. זו כתובת ה-URL שצפויה להיטען כשמשתמש פותח את התוסף. לצורך ההסבר הזה, צריך להזין https://<your domain>/addon-discovery.

  • ההגדרה Allowed Attachment URI Prefixes משמשת לאימות של ה-URI שמוגדר ב-AddOnAttachment באמצעות השיטות courses.*.addOnAttachments.create ו-courses.*.addOnAttachments.patch. האימות הוא התאמה מדויקת של מחרוזת קידומת, ובשלב הזה אי אפשר להשתמש בתווים כלליים. מוסיפים לפחות את דומיין הבסיס של שרת התוכן, כמו https://localhost:5000/ או https://cdn.myedtech.com/.

  • מוסיפים את אותם היקפי הרשאות של OAuth שמופיעים במסך ההסכמה ל-OAuth בשלב הקודם.

  • ממלאים את השדות בהתאם לארגון בקטע Developer Links (קישורים למפתחים).

רישום חנות

עוברים לדף Store Listing (דף העסקי בחנות) של Marketplace SDK. עליך לספק את הפרטים הבאים:

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

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

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

עוברים לדף היצירה של מסך ההסכמה ל-OAuth. עליך לספק את הפרטים הבאים:

  • מגדירים את סוג המשתמש בתור חיצוני. לוחצים על יצירה.
  • בדף הבא, ממלאים את פרטי האפליקציה הנדרשים ואת פרטי הקשר. מזינים את הדומיינים שבהם מתארחת האפליקציה בקטע דומיינים מורשים. לוחצים על שמירה והמשך.
  • מוסיפים את היקפי ההרשאות של OAuth שאפליקציית האינטרנט דורשת. במדריך להגדרת OAuth יש הסבר מפורט על היקפי הרשאות והמטרה שלהם.

    כדי ש-Google תשלח את פרמטר השאילתה login_hint, צריך לבקש לפחות אחת מההרשאות הבאות. הסבר מפורט יותר על ההתנהגות הזו זמין במדריך להגדרת OAuth:

    • https://www.googleapis.com/auth/userinfo.email (כבר כלול)
    • https://www.googleapis.com/auth/userinfo.profile (כבר כלול)

    ההיקפים הבאים ספציפיים לתוספים ל-Classroom:

    • https://www.googleapis.com/auth/classroom.addons.teacher
    • https://www.googleapis.com/auth/classroom.addons.student

    צריך לכלול גם היקפי הרשאות של Google API אחרים שהאפליקציה דורשת ממשתמשי הקצה.

    לוחצים על שמור והמשך.

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

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

התקנת התוסף

עכשיו אפשר להתקין את התוסף באמצעות הקישור בחלק העליון של הדף Store Listing (דף האפליקציה בחנות) ב-Marketplace SDK. לוחצים על הצגה ב-Marketplace בחלק העליון של הדף כדי לראות את הרישום, ואז בוחרים באפשרות התקנה.

באותו דומיין כמו הפרויקט ב-Cloud.

פיתוח אפליקציית אינטרנט בסיסית

הגדרת אפליקציית אינטרנט בסיסית עם שני נתיבים. השלבים הבאים במדריך הזה ירחיבו את האפליקציה הזו, אז בינתיים רק תיצור דף נחיתה לתוסף /addon-discovery ודף אינדקס לדוגמה / עבור 'האתר של החברה'.

דוגמה לאפליקציית אינטרנט ב-iframe

מטמיעים את שתי נקודות הקצה האלה:

  • /: מוצגת הודעת פתיחה ולחצן לסגירת הכרטיסייה הנוכחית ומסגרת ה-iframe של התוסף.
  • /addon-discovery: מוצגת הודעת פתיחה ושני לחצנים: אחד לסגירת ה-iframe של התוסף ואחד לפתיחת אתר בכרטיסייה חדשה.

שימו לב שאנחנו מוסיפים לחצנים ליצירה ולסגירה של חלונות או של iframe. הדוגמאות האלה מדגימות שיטה להעברת המשתמש בצורה בטוחה לכרטיסייה חדשה לצורך הרשאה בהדרכה הבאה.

יצירת סקריפט לכלי עזר

יוצרים ספרייה בשם static/scripts. יוצרים קובץ חדש addon-utils.js. מוסיפים את שתי הפונקציות הבאות.

/**
 *   Opens a given destination route in a new window. This function uses
 *   window.open() so as to force window.opener to retain a reference to the
 *   iframe from which it was called.
 *   @param {string} destinationURL The endpoint to open, or "/" if none is
 *   provided.
 */
function openWebsiteInNewTab(destinationURL = '/') {
  window.open(destinationURL, '_blank');
}

/**
 *   Close the iframe by calling postMessage() in the host Classroom page. This
 *   function can be called directly when in a Classroom add-on iframe.
 *
 *   Alternatively, it can be used to close an add-on iframe in another window.
 *   For example, if an add-on iframe in Window 1 opens a link in a new Window 2
 *   using the openWebsiteInNewTab function, you can call
 *   window.opener.closeAddonIframe() from Window 2 to close the iframe in Window
 *   1.
 */
function closeAddonIframe() {
  window.parent.postMessage({
    type: 'Classroom',
    action: 'closeIframe',
  }, '*');
};

יצירת מסלולים

מטמיעים את נקודות הקצה /addon-discovery ו-/.

Python

הגדרת ספריית האפליקציות

לצורך הדוגמה הזו, נגדיר את הלוגיקה של האפליקציה כמודול Python. זוהי הספריה webapp בדוגמה שסיפקנו.

יוצרים ספרייה למודול השרת, למשל webapp. מעבירים את הספרייה static לספריית המודול. יוצרים ספרייה בשם template בספריית המודול, ומעבירים אליה את קובצי ה-HTML.

בניית מודול השרת*

יוצרים את הקובץ __init__.py בספריית המודולים ומוסיפים את ההצהרות והייבוא הבאים.

from flask import Flask
import config

app = Flask(__name__)
app.config.from_object(config.Config)

# Load other module script files. This import statement refers to the
# 'routes.py' file described below.
from webapp import routes

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

from webapp import app
import flask

@app.route("/")
def index():
    return flask.render_template("index.html",
                                message="You've reached the index page.")

@app.route("/classroom-addon")
def classroom_addon():
    return flask.render_template(
        "addon-discovery.html",
        message="You've reached the addon discovery page.")

שימו לב ששני המסלולים מעבירים משתנה message לתבניות Jinja המתאימות. השדה הזה שימושי כדי לזהות לאיזה דף המשתמש הגיע.

יצירת קובצי תצורה והפעלה

בתיקיית השורש של האפליקציה, יוצרים את הקבצים main.py ו-config.py. מגדירים את המפתח הסודי ב-config.py.

import os

class Config(object):
    # Note: A secret key is included in the sample so that it works.
    # If you use this code in your application, replace this with a truly secret
    # key. See https://flask.palletsprojects.com/quickstart/#sessions.
    SECRET_KEY = os.environ.get(
        'SECRET_KEY') or "REPLACE ME - this value is here as a placeholder."

בקובץ main.py, מייבאים את המודול ומפעילים את שרת Flask.

from webapp import app

if __name__ == "__main__":
    # Run the application over HTTPs with a locally stored certificate and key.
    # Defaults to https://localhost:5000.
    app.run(
        host="localhost",
        ssl_context=("localhost.pem", "localhost-key.pem"),
        debug=True)

Node.js

המסלולים רשומים בקובץ app.js בשורות הבאות.

const websiteRouter = require('./routes/index');
const addonRouter = require('./routes/classroom-addon');

app.use('/', websiteRouter);
app.use('/addon-discovery', addonRouter);

פותחים את /01-basic-app/routes/index.js ובודקים את הקוד. הניתוב הזה מתבצע כשמשתמש קצה נכנס לאתר של החברה. המסלול מעבד תגובה באמצעות תבנית index Handlebars ומעביר לתבנית אובייקט נתונים שמכיל את המשתנים title ו-message.

router.get('/', function (req, res, next) {
  res.render('index', {
    title: 'Education Technology',
    message: 'Welcome to our website!'
  });
});

פותחים את המסלול השני /01-basic-app/routes/classroom-addon.js ובודקים את הקוד. הניתוב הזה מתבצע כשמשתמש הקצה מבקר בתוסף. שימו לב שהמסלול הזה משתמש בתבנית discovery Handlebars ובפריסת addon.hbs layout כדי להציג את הדף בצורה שונה מזו של אתר החברה.

router.get('/', function (req, res, next) {
  res.render('discovery', {
    layout: 'addon.hbs',
    title: 'Education Technology Classroom add-on',
    message: `Welcome.`
  });
});

Java

בדוגמת הקוד ב-Java נעשה שימוש במודולים כדי לארוז את השלבים של ההדרכה העקבית. מכיוון שזהו המדריך הראשון, הקוד נמצא במודול step_01_basic_app. לא מצופה מכם להטמיע את הפרויקט באמצעות מודולים. במקום זאת, מומלץ לבנות על פרויקט יחיד כשמבצעים כל שלב במדריך.

יוצרים מחלקה של בקר, Controller.java בפרויקט לדוגמה הזה, כדי להגדיר את נקודות הקצה. בקובץ הזה, מייבאים את ההערה @GetMapping מהתלות spring-boot-starter-web.

import org.springframework.web.bind.annotation.GetMapping;

כוללים את הערת הבקרה של Spring framework מעל הגדרת המחלקה כדי לציין את מטרת המחלקה.

@org.springframework.stereotype.Controller
public class Controller {

לאחר מכן מטמיעים את שני המסלולים ומסלול נוסף לטיפול בשגיאות.

/** Returns the index page that will be displayed when the add-on opens in a
*   new tab.
*   @param model the Model interface to pass error information that's
*   displayed on the error page.
*   @return the index page template if successful, or the onError method to
*   handle and display the error message.
*/
@GetMapping(value = {"/"})
public String index(Model model) {
  try {
    return "index";
  } catch (Exception e) {
    return onError(e.getMessage(), model);
  }
}

/** Returns the add-on discovery page that will be displayed when the iframe
*   is first opened in Classroom.
*   @param model the Model interface to pass error information that's
*   displayed on the error page.
*   @return the addon-discovery page.
*/
@GetMapping(value = {"/addon-discovery"})
public String addon_discovery(Model model) {
  try {
    return "addon-discovery";
  } catch (Exception e) {
    return onError(e.getMessage(), model);
  }
}

/** Handles application errors.
*   @param errorMessage message to be displayed on the error page.
*   @param model the Model interface to pass error information to display on
*   the error page.
*   @return the error page.
*/
@GetMapping(value = {"/error"})
public String onError(String errorMessage, Model model) {
  model.addAttribute("error", errorMessage);
  return "error";
}

בדיקת התוסף

מפעילים את השרת. לאחר מכן, נכנסים ל-Google Classroom בתור אחד ממשתמשי הבדיקה מסוג מורה. עוברים לכרטיסייה עבודות ויוצרים מטלה חדשה. בוחרים את התוסף מתוך בורר התוספים. ה-iframe נפתח והתוסף טוען את Attachment Setup URI שציינתם בדף App Configuration (הגדרת האפליקציה) ב-Marketplace SDK.

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