1. Przegląd
Z tego ćwiczenia w Codelabs dowiesz się, jak używać Prezentacji Google jako niestandardowego narzędzia do prezentacji analizy najpopularniejszych licencji na oprogramowanie. Za pomocą interfejsu BigQuery API będziesz wysyłać zapytania do całego kodu open source na GitHubie, a za pomocą interfejsu Google Slides API utworzysz prezentację, w której przedstawisz wyniki. Przykładowa aplikacja jest zbudowana przy użyciu Node.js, ale te same podstawowe zasady mają zastosowanie do każdej architektury.
Czego się nauczysz
- Tworzenie prezentacji za pomocą interfejsu Slides API
- Uzyskiwanie statystyk dotyczących dużego zbioru danych za pomocą BigQuery
- Kopiowanie pliku za pomocą interfejsu Google Drive API
Czego potrzebujesz
- Zainstalowane środowisko Node.js
- dostęp do internetu i przeglądarki;
- konto Google,
- Projekt Google Cloud Platform
2. Pobieranie przykładowego kodu
Możesz pobrać cały przykładowy kod na komputer...
…lub sklonuj repozytorium GitHub z poziomu wiersza poleceń.
git clone https://github.com/googleworkspace/slides-api.git
Repozytorium zawiera zestaw katalogów reprezentujących każdy etap procesu, dzięki czemu w razie potrzeby możesz odwołać się do działającej wersji.
Będziesz pracować na kopii znajdującej się w katalogu start, ale w razie potrzeby możesz odwoływać się do innych plików lub je kopiować.
3. Uruchamianie przykładowej aplikacji
Najpierw uruchom skrypt Node. Po pobraniu kodu wykonaj te instrukcje, aby zainstalować i uruchomić aplikację Node.js:
- Otwórz terminal wiersza poleceń na komputerze i przejdź do katalogu
startz ćwiczeniem. - Aby zainstalować zależności Node.js, wpisz to polecenie.
npm install
- Aby uruchomić skrypt, wpisz to polecenie:
node .
- Zapoznaj się z powitaniem, w którym znajdziesz instrukcje dotyczące tego projektu.
-- Start generating slides. --
TODO: Get Client Secrets
TODO: Authorize
TODO: Get Data from BigQuery
TODO: Create Slides
TODO: Open Slides
-- Finished generating slides. --
Naszą listę zadań znajdziesz w slides.js, license.js i auth.js. Pamiętaj, że do łączenia kroków potrzebnych do ukończenia aplikacji używamy obiektów Promise w JavaScript, ponieważ każdy krok zależy od ukończenia poprzedniego.
Jeśli nie znasz obietnic, nie martw się – udostępnimy Ci cały potrzebny kod. W skrócie: obietnice umożliwiają asynchroniczne przetwarzanie w sposób bardziej synchroniczny.
4. Pobieranie tajnych kluczy klienta
Aby korzystać z interfejsów API Prezentacji, BigQuery i Dysku, utworzymy klienta OAuth i konto usługi.
Konfigurowanie konsoli Google Developers Console
- Skorzystaj z tego kreatora, aby utworzyć lub wybrać projekt w Google Developers Console i automatycznie włączyć interfejs API. Kliknij kolejno Dalej i Przejdź do danych logowania.
- Na stronie Dodaj dane logowania do projektu kliknij przycisk Anuluj.
- U góry strony wybierz kartę Ekran zgody OAuth. Wybierz adres e-mail, wpisz nazwę produktu
Slides API Codelabi kliknij przycisk Zapisz.
Włączanie interfejsów BigQuery, Dysk i Prezentacje
- Wybierz kartę Panel, kliknij przycisk Włącz API i włącz te 3 interfejsy API:
- BigQuery API
- Google Drive API
- Google Slides API
Pobieranie tajnego klucza klienta OAuth (w przypadku Prezentacji i Dysku)
- Wybierz kartę Dane logowania, kliknij przycisk Utwórz dane logowania i wybierz Identyfikator klienta OAuth.
- Wybierz typ aplikacji Inne, wpisz nazwę
Google Slides API Codelabi kliknij przycisk Utwórz.Kliknij OK, aby zamknąć wyświetlone okno. - Kliknij przycisk file_download (Pobierz JSON) po prawej stronie identyfikatora klienta.
- Zmień nazwę pliku tajnego na
client_secret.jsoni skopiuj go do katalogów start/ i finish/.
Pobieranie klucza tajnego konta usługi (w przypadku BigQuery)
- Wybierz kartę Dane logowania, kliknij przycisk Utwórz dane logowania i wybierz Klucz konta usługi.
- W menu kliknij Nowe konto usługi. Wybierz nazwę
Slides API Codelab Servicedla usługi. Następnie kliknij Rola, przewiń do sekcji BigQuery i wybierz Wyświetlający dane BigQuery oraz Użytkownik zadań BigQuery. - W polu Typ klucza wybierz JSON.
- Kliknij Utwórz. Plik klucza zostanie automatycznie pobrany na komputer. Aby zamknąć okno, które się pojawi, kliknij Zamknij.
- Zmień nazwę pliku tajnego na
service_account_secret.jsoni skopiuj go do katalogów start/ i finish/.
Pobieranie tajnych kluczy klienta
W start/auth.js wypełnijmy metodę 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));
});
});
}
Tajne klucze klienta zostały wczytane. Dane logowania zostaną przekazane do następnej obietnicy. Uruchom projekt za pomocą przycisku node ., aby sprawdzić, czy nie ma błędów.
5. Tworzenie klienta OAuth2
Aby utworzyć slajdy, dodajmy uwierzytelnianie w interfejsach API Google, dodając ten kod do pliku auth.js. W ramach tego uwierzytelniania zostanie wysłana prośba o dostęp do Twojego konta Google w celu odczytywania i zapisywania plików na Dysku Google, tworzenia prezentacji w Prezentacjach Google oraz wykonywania zapytań tylko do odczytu w Google BigQuery. (Uwaga: nie zmieniliśmy 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. Konfigurowanie BigQuery
Poznaj BigQuery (opcjonalnie)
BigQuery umożliwia nam wysyłanie zapytań do ogromnych zbiorów danych w ciągu kilku sekund. Zanim przejdziemy do wysyłania zapytań programowych, użyjmy interfejsu internetowego. Jeśli nigdy wcześniej nie konfigurowałeś(-aś) BigQuery, wykonaj czynności opisane w tym krótkim wprowadzeniu.
Otwórz konsolę Cloud, aby przejrzeć dane GitHub dostępne w BigQuery i uruchomić własne zapytania. Aby dowiedzieć się, które licencje oprogramowania są najpopularniejsze na GitHubie, wpisz to zapytanie i kliknij przycisk Uruchom.
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
Przeanalizowaliśmy miliony publicznych repozytoriów w GitHubie i wybraliśmy najpopularniejsze licencje. Super! Teraz skonfigurujmy uruchamianie tego samego zapytania, ale tym razem programowo.
Konfigurowanie BigQuery
Zastąp kod w pliku license.js. Funkcja bigquery.query zwróci obietnicę.
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
});
});
});
}
Spróbuj console.log niektóre dane w funkcji zwrotnej Promise, aby poznać strukturę naszych obiektów i zobaczyć, jak działa kod.
7. Tworzenie prezentacji
A teraz czas na zabawę! Utwórzmy slajdy, wywołując metody create i batchUpdate interfejsu Slides API. Nasz plik powinien zostać zastąpiony tym:
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. Otwórz Prezentacje
Na koniec otwórz prezentację w przeglądarce. Zaktualizuj tę metodę w 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);
}
Uruchom projekt po raz ostatni, aby wyświetlić ostateczny wynik.
9. Gratulacje!
Udało Ci się wygenerować prezentację w Prezentacjach Google na podstawie danych przeanalizowanych za pomocą BigQuery. Skrypt tworzy prezentację za pomocą interfejsu Google Slides API i BigQuery, aby przedstawić analizę najpopularniejszych licencji na oprogramowanie.
Możliwe ulepszenia
Oto kilka dodatkowych pomysłów na jeszcze bardziej atrakcyjną integrację:
- Dodawanie obrazów do każdego slajdu
- Udostępnianie slajdów przez e-mail przy użyciu interfejsu Gmail API
- Dostosowywanie slajdu szablonu jako argumentu wiersza poleceń
Więcej informacji
- Zapoznaj się z dokumentacją interfejsu API Prezentacji Google dla programistów.
- Zadawaj pytania i szukaj odpowiedzi w witrynie Stack Overflow, używając tagu google-slides-api.