יצירת תוסף ל-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 v16.13 ואילך.

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

npm install

Java

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

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

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

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

java --version
./mvnw --version

או ב-Windows:

java -version
mvnw.cmd --version

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

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

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

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

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

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

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

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

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

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

  • מגדירים את User Type (סוג המשתמש) בתור External (חיצוני). לוחצים על יצירה.
  • בדף הבא, ממלאים את פרטי האפליקציה הנדרשים ואת פרטי יצירת הקשר. בשדה דומיינים מורשים, מציינים את כל הדומיינים שבהם מתארחת האפליקציה. לוחצים על שמירה והמשך.
  • מוסיפים את היקפי ההרשאות של 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 בחלק העליון של הדף כדי לראות את רשימת התוספים, ואז בוחרים באפשרות התקנה.

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

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

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 נפתח והתוסף טוען את ה-URI של הגדרת הקובץ המצורף שציינתם בדף App Configuration (הגדרת האפליקציה) ב-Marketplace SDK.

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