1. סקירה כללית
ב-codelab הזה נסביר איך אפשר להשתמש ב-Google Slides ככלי מותאם אישית ליצירת מצגות לצורך ניתוח של רישיונות התוכנה הנפוצים ביותר. תשאלו שאילתות על כל הקוד הפתוח ב-GitHub באמצעות BigQuery API ותיצרו מצגת באמצעות Google Slides API כדי להציג את התוצאות. אפליקציית הדוגמה בנויה באמצעות Node.js, אבל אותם עקרונות בסיסיים רלוונטיים לכל ארכיטקטורה.
מה תלמדו
- יצירת מצגות באמצעות Slides API
- שימוש ב-BigQuery כדי לקבל תובנות לגבי מערך נתונים גדול
- העתקת קובץ באמצעות Google Drive API
הדרישות
- Node.js מותקן
- גישה לאינטרנט ולדפדפן אינטרנט
- חשבון Google
- פרויקט ב-Google Cloud Platform
2. קבלת קוד לדוגמה
אפשר להוריד את כל הקוד לדוגמה למחשב...
…או משכפלים את המאגר ב-GitHub משורת הפקודה.
git clone https://github.com/googleworkspace/slides-api.git
המאגר מכיל קבוצה של ספריות שמייצגות כל שלב בתהליך, למקרה שתצטרכו לעיין בגרסה פעילה.
תעבדו על העותק שנמצא בספרייה start, אבל תוכלו לעיין בקבצים האחרים או להעתיק מהם לפי הצורך.
3. הרצת האפליקציה לדוגמה
קודם כול צריך להפעיל את סקריפט Node. אחרי שמורידים את הקוד, פועלים לפי ההוראות הבאות כדי להתקין ולהפעיל את אפליקציית Node.js:
- פותחים טרמינל של שורת פקודה במחשב ועוברים לספרייה
startשל ה-codelab. - מזינים את הפקודה הבאה כדי להתקין את יחסי התלות של Node.js.
npm install
- מזינים את הפקודה הבאה כדי להריץ את הסקריפט:
node .
- קוראים את ההודעה שמופיעה עם השלבים לפרויקט הזה.
-- Start generating slides. --
TODO: Get Client Secrets
TODO: Authorize
TODO: Get Data from BigQuery
TODO: Create Slides
TODO: Open Slides
-- Finished generating slides. --
אפשר לראות את רשימת המשימות שלנו ב-slides.js, ב-license.js וב-auth.js. שימו לב: אנחנו משתמשים ב-JavaScript Promises כדי לשרשר את השלבים שנדרשים להשלמת האפליקציה, כי כל שלב תלוי בהשלמת השלב הקודם.
אם אתם לא מכירים את המושג Promises, אל דאגה, נספק לכם את כל הקוד שתצטרכו. בקיצור, הבטחות מאפשרות לנו לטפל בעיבוד אסינכרוני בצורה סינכרונית יותר.
4. קבלת סודות לקוח
כדי להשתמש בממשקי Slides, BigQuery ו-Drive API, ניצור לקוח OAuth וחשבון שירות.
הגדרת Google Developers Console
- משתמשים באשף הזה כדי ליצור או לבחור פרויקט ב-Google Developers Console ולהפעיל את ה-API באופן אוטומטי. לוחצים על המשך ואז על מעבר לפרטי הכניסה.
- בדף הוספת פרטי כניסה לפרויקט, לוחצים על הלחצן ביטול.
- בחלק העליון של הדף, לוחצים על הכרטיסייה מסך הסכמה ל-OAuth. בוחרים כתובת אימייל, מזינים את שם המוצר
Slides API Codelabולוחצים על הלחצן שמירה.
הפעלת BigQuery, Drive ו-Slides APIs
- בוחרים בכרטיסייה Dashboard, לוחצים על הלחצן Enable API ומפעילים את 3 ממשקי ה-API הבאים:
- BigQuery API
- Google Drive API
- Google Slides API
הורדת סוד של לקוח OAuth (ל-Slides ול-Drive)
- בוחרים בכרטיסייה Credentials (פרטי כניסה), לוחצים על הלחצן Create credentials (יצירת פרטי כניסה) ובוחרים באפשרות OAuth client ID (מזהה לקוח OAuth).
- בוחרים בסוג האפליקציה אחר, מזינים את השם
Google Slides API Codelabולוחצים על הלחצן יצירה.לוחצים על אישור כדי לסגור את תיבת הדו-שיח שמופיעה. - לוחצים על הלחצן file_download (הורדת JSON) משמאל למזהה הלקוח.
- משנים את השם של קובץ הסוד ל-
client_secret.jsonומעתיקים אותו לספריות start/ ו-finish/.
הורדת סוד של חשבון שירות (ל-BigQuery)
- בוחרים בכרטיסייה Credentials, לוחצים על הלחצן Create credentials ובוחרים באפשרות Service account key.
- בתפריט הנפתח, בוחרים באפשרות New Service Account (חשבון שירות חדש). בוחרים שם
Slides API Codelab Serviceלשירות. אחר כך לוחצים על תפקיד, גוללים אל BigQuery ובוחרים גם בBigQuery Data Viewer וגם בBigQuery Job User. - בקטע Key type (סוג המפתח), בוחרים באפשרות JSON.
- לוחצים על יצירה. קובץ המפתח יורד אוטומטית למחשב. לוחצים על סגירה כדי לצאת מתיבת הדו-שיח שמופיעה.
- משנים את השם של קובץ הסוד ל-
service_account_secret.jsonומעתיקים אותו לספריות start/ ו-finish/.
קבלת סודות לקוח
ב-start/auth.js, נמלא את השיטה getClientSecrets.
auth.js
const fs = require('fs');
/**
* Loads client secrets from a local file.
* @return {Promise} A promise to return the secrets.
*/
module.exports.getClientSecrets = () => {
return new Promise((resolve, reject) => {
fs.readFile('client_secret.json', (err, content) => {
if (err) return reject('Error loading client secret file: ' + err);
console.log('loaded secrets...');
resolve(JSON.parse(content));
});
});
}
עכשיו סודות הלקוח נטענו. הפרטים יועברו לאובייקט ה-promise הבא. מריצים את הפרויקט עם node . כדי לוודא שאין שגיאות.
5. יצירת לקוח OAuth2
כדי ליצור שקפים, נוסיף אימות לממשקי Google API על ידי הוספת הקוד הבא לקובץ auth.js. במהלך האימות הזה תתבקשו לתת גישה לחשבון Google שלכם כדי לקרוא ולכתוב קבצים ב-Google Drive, ליצור מצגות ב-Google Slides ולהריץ שאילתות לקריאה בלבד מ-Google BigQuery. (הערה: לא שינינו את getClientSecrets)
auth.js
const fs = require('fs');
const readline = require('readline');
const openurl = require('openurl');
const googleAuth = require('google-auth-library');
const TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
const TOKEN_PATH = TOKEN_DIR + 'slides.googleapis.com-nodejs-quickstart.json';
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/slides.googleapis.com-nodejs-quickstart.json
const SCOPES = [
'https://www.googleapis.com/auth/presentations', // needed to create slides
'https://www.googleapis.com/auth/drive', // read and write files
'https://www.googleapis.com/auth/bigquery.readonly' // needed for bigquery
];
/**
* Loads client secrets from a local file.
* @return {Promise} A promise to return the secrets.
*/
module.exports.getClientSecrets = () => {
return new Promise((resolve, reject) => {
fs.readFile('client_secret.json', (err, content) => {
if (err) return reject('Error loading client secret file: ' + err);
console.log('loaded secrets...');
resolve(JSON.parse(content));
});
});
}
/**
* Create an OAuth2 client promise with the given credentials.
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback for the authorized client.
* @return {Promise} A promise to return the OAuth client.
*/
module.exports.authorize = (credentials) => {
return new Promise((resolve, reject) => {
console.log('authorizing...');
const clientSecret = credentials.installed.client_secret;
const clientId = credentials.installed.client_id;
const redirectUrl = credentials.installed.redirect_uris[0];
const auth = new googleAuth();
const oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) {
getNewToken(oauth2Client).then(() => {
resolve(oauth2Client);
});
} else {
oauth2Client.credentials = JSON.parse(token);
resolve(oauth2Client);
}
});
});
}
/**
* Get and store new token after prompting for user authorization, and then
* fulfills the promise. Modifies the `oauth2Client` object.
* @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* @return {Promise} A promise to modify the oauth2Client credentials.
*/
function getNewToken(oauth2Client) {
console.log('getting new auth token...');
openurl.open(oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
}));
console.log(''); // \n
return new Promise((resolve, reject) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oauth2Client.getToken(code, (err, token) => {
if (err) return reject(err);
oauth2Client.credentials = token;
let storeTokenErr = storeToken(token);
if (storeTokenErr) return reject(storeTokenErr);
resolve();
});
});
});
}
/**
* Store token to disk be used in later program executions.
* @param {Object} token The token to store to disk.
* @return {Error?} Returns an error or undefined if there is no error.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
fs.writeFileSync(TOKEN_PATH, JSON.stringify(token));
} catch (err) {
if (err.code != 'EEXIST') return err;
}
console.log('Token stored to ' + TOKEN_PATH);
}
6. הגדרת BigQuery
התנסות ב-BigQuery (אופציונלי)
BigQuery מאפשר לנו להריץ שאילתות על מערכי נתונים עצומים תוך שניות. לפני ששולחים שאילתה באופן פרוגרמטי, כדאי להשתמש בממשק האינטרנט. אם זו הפעם הראשונה שאתם מגדירים את BigQuery, פועלים לפי השלבים במדריך למתחילים.
אפשר לפתוח את Cloud Console כדי לעיין בנתוני GitHub שזמינים ב-BigQuery ולהריץ שאילתות משלכם. כדי לגלות אילו רישיונות תוכנה הם הכי פופולריים ב-GitHub, כותבים את השאילתה הבאה ולוחצים על הלחצן הפעלה.
bigquery.sql
WITH AllLicenses AS (
SELECT * FROM `bigquery-public-data.github_repos.licenses`
)
SELECT
license,
COUNT(*) AS count,
ROUND((COUNT(*) / (SELECT COUNT(*) FROM AllLicenses)) * 100, 2) AS percent
FROM `bigquery-public-data.github_repos.licenses`
GROUP BY license
ORDER BY count DESC
LIMIT 10
הרגע סיימנו לנתח מיליוני מאגרי קוד ציבוריים ב-GitHub, וגילינו אילו רישיונות הם הכי פופולריים. מגניב! עכשיו נגדיר הרצה של אותה שאילתה, אבל הפעם באופן פרוגרמטי.
הגדרת BigQuery
מחליפים את הקוד בקובץ license.js. הפונקציה bigquery.query תחזיר promise.
license**.js**
const google = require('googleapis');
const read = require('read-file');
const BigQuery = require('@google-cloud/bigquery');
const bigquery = BigQuery({
credentials: require('./service_account_secret.json')
});
// See codelab for other queries.
const query = `
WITH AllLicenses AS (
SELECT * FROM \`bigquery-public-data.github_repos.licenses\`
)
SELECT
license,
COUNT(*) AS count,
ROUND((COUNT(*) / (SELECT COUNT(*) FROM AllLicenses)) * 100, 2) AS percent
FROM \`bigquery-public-data.github_repos.licenses\`
GROUP BY license
ORDER BY count DESC
LIMIT 10
`;
/**
* Get the license data from BigQuery and our license data.
* @return {Promise} A promise to return an object of licenses keyed by name.
*/
module.exports.getLicenseData = (auth) => {
console.log('querying BigQuery...');
return bigquery.query({
query,
useLegacySql: false,
useQueryCache: true,
}).then(bqData => Promise.all(bqData[0].map(getLicenseText)))
.then(licenseData => new Promise((resolve, reject) => {
resolve([auth, licenseData]);
}))
.catch((err) => console.error('BigQuery error:', err));
}
/**
* Gets a promise to get the license text about a license
* @param {object} licenseDatum An object with the license's
* `license`, `count`, and `percent`
* @return {Promise} A promise to return license data with license text.
*/
function getLicenseText(licenseDatum) {
const licenseName = licenseDatum.license;
return new Promise((resolve, reject) => {
read(`licenses/${licenseName}.txt`, 'utf8', (err, buffer) => {
if (err) return reject(err);
resolve({
licenseName,
count: licenseDatum.count,
percent: licenseDatum.percent,
license: buffer.substring(0, 1200) // first 1200 characters
});
});
});
}
נסו console.log חלק מהנתונים בתוך הקריאה החוזרת (callback) של Promise כדי להבין את המבנה של האובייקטים שלנו ולראות את הקוד בפעולה.
7. יצירת שקפים
ועכשיו לחלק הכיפי! ניצור שקופיות באמצעות קריאה ל-methods create ו-batchUpdate של Slides API. צריך להחליף את הקובץ שלנו בתוכן הבא:
slides.js
const google = require('googleapis');
const slides = google.slides('v1');
const drive = google.drive('v3');
const openurl = require('openurl');
const commaNumber = require('comma-number');
const SLIDE_TITLE_TEXT = 'Open Source Licenses Analysis';
/**
* Get a single slide json request
* @param {object} licenseData data about the license
* @param {object} index the slide index
* @return {object} The json for the Slides API
* @example licenseData: {
* "licenseName": "mit",
* "percent": "12.5",
* "count": "1667029"
* license:"<body>"
* }
* @example index: 3
*/
function createSlideJSON(licenseData, index) {
// Then update the slides.
const ID_TITLE_SLIDE = 'id_title_slide';
const ID_TITLE_SLIDE_TITLE = 'id_title_slide_title';
const ID_TITLE_SLIDE_BODY = 'id_title_slide_body';
return [{
// Creates a "TITLE_AND_BODY" slide with objectId references
createSlide: {
objectId: `${ID_TITLE_SLIDE}_${index}`,
slideLayoutReference: {
predefinedLayout: 'TITLE_AND_BODY'
},
placeholderIdMappings: [{
layoutPlaceholder: {
type: 'TITLE'
},
objectId: `${ID_TITLE_SLIDE_TITLE}_${index}`
}, {
layoutPlaceholder: {
type: 'BODY'
},
objectId: `${ID_TITLE_SLIDE_BODY}_${index}`
}]
}
}, {
// Inserts the license name, percent, and count in the title
insertText: {
objectId: `${ID_TITLE_SLIDE_TITLE}_${index}`,
text: `#${index + 1} ${licenseData.licenseName} — ~${licenseData.percent}% (${commaNumber(licenseData.count)} repos)`
}
}, {
// Inserts the license in the text body paragraph
insertText: {
objectId: `${ID_TITLE_SLIDE_BODY}_${index}`,
text: licenseData.license
}
}, {
// Formats the slide paragraph's font
updateParagraphStyle: {
objectId: `${ID_TITLE_SLIDE_BODY}_${index}`,
fields: '*',
style: {
lineSpacing: 10,
spaceAbove: {magnitude: 0, unit: 'PT'},
spaceBelow: {magnitude: 0, unit: 'PT'},
}
}
}, {
// Formats the slide text style
updateTextStyle: {
objectId: `${ID_TITLE_SLIDE_BODY}_${index}`,
style: {
bold: true,
italic: true,
fontSize: {
magnitude: 10,
unit: 'PT'
}
},
fields: '*',
}
}];
}
/**
* Creates slides for our presentation.
* @param {authAndGHData} An array with our Auth object and the GitHub data.
* @return {Promise} A promise to return a new presentation.
* @see https://developers.google.com/apis-explorer/#p/slides/v1/
*/
module.exports.createSlides = (authAndGHData) => new Promise((resolve, reject) => {
console.log('creating slides...');
const [auth, ghData] = authAndGHData;
// First copy the template slide from drive.
drive.files.copy({
auth: auth,
fileId: '1toV2zL0PrXJOfFJU-NYDKbPx9W0C4I-I8iT85TS0fik',
fields: 'id,name,webViewLink',
resource: {
name: SLIDE_TITLE_TEXT
}
}, (err, presentation) => {
if (err) return reject(err);
const allSlides = ghData.map((data, index) => createSlideJSON(data, index));
slideRequests = [].concat.apply([], allSlides); // flatten the slide requests
slideRequests.push({
replaceAllText: {
replaceText: SLIDE_TITLE_TEXT,
containsText: { text: '{{TITLE}}' }
}
})
// Execute the requests
slides.presentations.batchUpdate({
auth: auth,
presentationId: presentation.id,
resource: {
requests: slideRequests
}
}, (err, res) => {
if (err) {
reject(err);
} else {
resolve(presentation);
}
});
});
});
8. פתיחת Slides
לסיום, נפתח את המצגת בדפדפן. צריך לעדכן את אמצעי התשלום הבא ב-slides.js.
slides.js
/**
* Opens a presentation in a browser.
* @param {String} presentation The presentation object.
*/
module.exports.openSlidesInBrowser = (presentation) => {
console.log('Presentation URL:', presentation.webViewLink);
openurl.open(presentation.webViewLink);
}
מריצים את הפרויקט בפעם האחרונה כדי לראות את התוצאה הסופית.
9. מעולה!
יצרתם בהצלחה מצגת ב-Google Slides מנתונים שנותחו באמצעות BigQuery. הסקריפט יוצר מצגת באמצעות Google Slides API ו-BigQuery כדי לדווח על ניתוח של רישיונות התוכנה הנפוצים ביותר.
שיפורים אפשריים
הנה עוד כמה רעיונות לשילוב מוצלח יותר:
- הוספת תמונות לכל שקף
- שיתוף שקפים באימייל באמצעות Gmail API
- התאמה אישית של שקף התבנית כארגומנט של שורת פקודה
מידע נוסף
- קראו את התיעוד למפתחים של Google Slides API.
- אפשר לפרסם שאלות ולמצוא תשובות ב-Stack Overflow באמצעות התג google-slides-api.