Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Node-1st-gen/bigquery-import/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ As an example we'll be using a simple logs database structure:
Set the `bigquery.datasetName` and `bigquery.tableName` Google Cloud environment variables to match the Dataset name and the Table name where you want the logs written to. For this use:

```bash
firebase functions:config:set bigquery.datasetName="bar" bigquery.tableName="baz"
Add the following configuration to your `.env` file:
```
BIGQUERY_DATASETNAME="bar"
BIGQUERY_TABLENAME="baz"
```
```
12 changes: 8 additions & 4 deletions Node-1st-gen/bigquery-import/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,22 @@
'use strict';

const functions = require('firebase-functions/v1');
const {defineString} = require('firebase-functions/params');
const { BigQuery } = require('@google-cloud/bigquery');

const bigquery = new BigQuery();

const bigqueryDatasetname = defineString('BIGQUERY_DATASETNAME');
const bigqueryTablename = defineString('BIGQUERY_TABLENAME');

/**
* Writes all logs from the Realtime Database into bigquery.
*/
exports.addtobigquery = functions.database.ref('/logs/{logid}').onCreate((snapshot) => {
// TODO: Make sure you set the `bigquery.datasetName` Google Cloud environment variable.
const dataset = bigquery.dataset(functions.config().bigquery.datasetname);
// TODO: Make sure you set the `bigquery.tableName` Google Cloud environment variable.
const table = dataset.table(functions.config().bigquery.tablename);
// TODO: Make sure you set the `BIGQUERY_DATASETNAME` environment variable.
const dataset = bigquery.dataset(bigqueryDatasetname.value());
// TODO: Make sure you set the `BIGQUERY_TABLENAME` environment variable.
const table = dataset.table(bigqueryTablename.value());

return table.insert({
ID: snapshot.key,
Expand Down
2 changes: 1 addition & 1 deletion Node-1st-gen/developer-motivator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To deploy and test the sample:
- Set the `dev_motivator.device_token` Google Cloud environment variables. For this use:
```bash
firebase functions:config:set dev_motivator.device_token="your_developer_device_token"
firebase functions:secrets:set DEV_MOTIVATOR_DEVICE_TOKEN
```
- Deploy your project's code using `firebase deploy`
- You'll now get a notification on your mobile when a user opens your app for the first time and when they uninstall your app.
Expand Down
13 changes: 7 additions & 6 deletions Node-1st-gen/developer-motivator/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@

const admin = require('firebase-admin');
const functions = require('firebase-functions/v1');
const {defineSecret} = require('firebase-functions/params');
admin.initializeApp();

// TODO: Make sure you configure the 'dev_motivator.device_token' Google Cloud environment variables.
const deviceToken = functions.config().dev_motivator.device_token;
// TODO: Make sure you configure the 'DEV_MOTIVATOR_DEVICE_TOKEN' secret.
const devMotivatorDeviceToken = defineSecret('DEV_MOTIVATOR_DEVICE_TOKEN');

/**
* Triggers when the app is opened the first time in a user device and sends a notification to your developer device.
*
* The device model name, the city and the country of the user are sent in the notification message
*/
exports.appinstalled = functions.analytics.event('first_open').onLog((event) => {
exports.appinstalled = functions.runWith({secrets: [devMotivatorDeviceToken]}).analytics.event('first_open').onLog((event) => {
const user = event.user;
const payload = {
notification: {
Expand All @@ -36,7 +37,7 @@ exports.appinstalled = functions.analytics.event('first_open').onLog((event) =>
}
};

return admin.messaging().send({token: deviceToken, notification: payload.notification});
return admin.messaging().send({token: devMotivatorDeviceToken.value(), notification: payload.notification});
});

/**
Expand All @@ -46,7 +47,7 @@ exports.appinstalled = functions.analytics.event('first_open').onLog((event) =>
*
* The device model name, the city and the country of the user are sent in the notification message
*/
exports.appremoved = functions.analytics.event('app_remove').onLog((event) => {
exports.appremoved = functions.runWith({secrets: [devMotivatorDeviceToken]}).analytics.event('app_remove').onLog((event) => {
const user = event.user;
const payload = {
notification: {
Expand All @@ -55,5 +56,5 @@ exports.appremoved = functions.analytics.event('app_remove').onLog((event) => {
}
};

return admin.messaging().send({token: deviceToken, notification: payload.notification});
return admin.messaging().send({token: devMotivatorDeviceToken.value(), notification: payload.notification});
});
9 changes: 8 additions & 1 deletion Node-1st-gen/email-confirmation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ The function triggers on changes to `/users/$uid` and exits if there are no chan
1. To be able to send emails with your Gmail account: enable access to [Less Secure Apps](https://www.google.com/settings/security/lesssecureapps) and [Display Unlock Captcha](https://accounts.google.com/DisplayUnlockCaptcha). For accounts with 2-step verification enabled [Generate an App Password](https://support.google.com/accounts/answer/185833).
1. Set the `gmail.email` and `gmail.password` Google Cloud environment variables to match the email and password of the Gmail account used to send emails (or the app password if your account has 2-step verification enabled). For this use:
```bash
firebase functions:config:set gmail.email="myusername@gmail.com" gmail.password="secretpassword"
Add the following configuration to your `.env` file:
```
GMAIL_EMAIL="myusername@gmail.com"
```
Then, set the `GMAIL_PASSWORD` secret:
```
firebase functions:secrets:set GMAIL_PASSWORD
```
```

## Deploy and test
Expand Down
26 changes: 16 additions & 10 deletions Node-1st-gen/email-confirmation/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,28 @@
'use strict';

const functions = require('firebase-functions/v1');
const {onInit} = require('firebase-functions/v1/init');
const {defineString, defineSecret} = require('firebase-functions/params');
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail,
pass: gmailPassword,
},
// TODO: Configure the `GMAIL_EMAIL` environment variable and the `GMAIL_PASSWORD` secret.
const gmailEmail = defineString('GMAIL_EMAIL');
const gmailPassword = defineSecret('GMAIL_PASSWORD');

let mailTransport;
onInit(() => {
mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
user: gmailEmail.value(),
pass: gmailPassword.value(),
},
});
});

// Sends an email confirmation when a user changes his mailing list subscription.
exports.sendEmailConfirmation = functions.database.ref('/users/{uid}').onWrite(async (change) => {
exports.sendEmailConfirmation = functions.runWith({secrets: [gmailPassword]}).database.ref('/users/{uid}').onWrite(async (change) => {
// Early exit if the 'subscribedToMailingList' field has not changed
if (change.after.child('subscribedToMailingList').val() === change.before.child('subscribedToMailingList').val()) {
return null;
Expand Down
27 changes: 16 additions & 11 deletions Node-1st-gen/fulltext-search-firestore/functions/elastic.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/
const functions = require('firebase-functions/v1');
const {onInit} = require('firebase-functions/v1/init');
const {defineString, defineSecret} = require('firebase-functions/params');

// [START init_elastic]
const { Client } = require("@elastic/elasticsearch");
Expand All @@ -22,22 +24,25 @@ const { Client } = require("@elastic/elasticsearch");
// https://github.com/elastic/elasticsearch-js
//
// ID, username, and password are stored in functions config variables
const ELASTIC_ID = functions.config().elastic.id;
const ELASTIC_USERNAME = functions.config().elastic.username;
const ELASTIC_PASSWORD = functions.config().elastic.password;
const elasticId = defineString('ELASTIC_ID');
const elasticUsername = defineString('ELASTIC_USERNAME');
const elasticPassword = defineSecret('ELASTIC_PASSWORD');

const client = new Client({
cloud: {
id: ELASTIC_ID,
username: ELASTIC_USERNAME,
password: ELASTIC_PASSWORD,
}
let client;
onInit(() => {
client = new Client({
cloud: {
id: elasticId.value(),
username: elasticUsername.value(),
password: elasticPassword.value(),
}
});
});
// [END init_elastic]

// [START update_index_function_elastic]
// Update the search index every time a blog post is written.
exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(async (snap, context) => {
exports.onNoteCreated = functions.runWith({secrets: [elasticPassword]}).firestore.document('notes/{noteId}').onCreate(async (snap, context) => {
// Get the note document
const note = snap.data();

Expand All @@ -54,7 +59,7 @@ exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(
// [END update_index_function_elastic]

// [START search_function_elastic]
exports.searchNotes = functions.https.onCall(async (data, context) => {
exports.searchNotes = functions.runWith({secrets: [elasticPassword]}).https.onCall(async (data, context) => {
const query = data.query;

// Search for any notes where the text field contains the query text.
Expand Down
20 changes: 13 additions & 7 deletions Node-1st-gen/fulltext-search-firestore/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,30 @@
* limitations under the License.
*/
const functions = require('firebase-functions/v1');
const {onInit} = require('firebase-functions/v1/init');
const {defineSecret} = require('firebase-functions/params');
const algoliasearch = require('algoliasearch').default;

// [START init_algolia]
// Initialize Algolia, requires installing Algolia dependencies:
// https://www.algolia.com/doc/api-client/javascript/getting-started/#install
//
// App ID and API Key are stored in functions config variables
const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;
const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;
const algoliaId = defineSecret('ALGOLIA_ID');
const algoliaAdminKey = defineSecret('ALGOLIA_ADMIN_KEY');
const algoliaSearchKey = defineSecret('ALGOLIA_SEARCH_KEY');

const ALGOLIA_INDEX_NAME = 'notes';
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);

let client;
onInit(() => {
client = algoliasearch(algoliaId.value(), algoliaAdminKey.value());
});
// [END init_algolia]

// [START update_index_function]
// Update the search index every time a blog post is written.
exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate((snap, context) => {
exports.onNoteCreated = functions.runWith({secrets: [algoliaId, algoliaAdminKey]}).firestore.document('notes/{noteId}').onCreate((snap, context) => {
// Get the note document
const note = snap.data();

Expand Down Expand Up @@ -108,13 +114,13 @@ app.get('/', (req, res) => {
};

// Call the Algolia API to generate a unique key based on our search key
const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);
const key = client.generateSecuredApiKey(algoliaSearchKey.value(), params);

// Then return this key as {key: '...key'}
res.json({key});
});

// Finally, pass our ExpressJS app to Cloud Functions as a function
// called 'getSearchKey';
exports.getSearchKey = functions.https.onRequest(app);
exports.getSearchKey = functions.runWith({secrets: [algoliaId, algoliaAdminKey, algoliaSearchKey]}).https.onRequest(app);
// [END get_algolia_user_token]
51 changes: 18 additions & 33 deletions Node-1st-gen/fulltext-search-firestore/functions/typesense.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,35 @@
* limitations under the License.
*/
const functions = require('firebase-functions/v1');
const {onInit} = require('firebase-functions/v1/init');
const {defineSecret} = require('firebase-functions/params');

// [START init_typesense]
// Initialize Typesense, requires installing Typesense dependencies:
// https://github.com/typesense/typesense-js
const Typesense = require("typesense");

// Typesense API keys are stored in functions config variables
const TYPESENSE_ADMIN_API_KEY = functions.config().typesense.admin_api_key;
const TYPESENSE_SEARCH_API_KEY = functions.config().typesense.search_api_key;
const typesenseAdminApiKey = defineSecret('TYPESENSE_ADMIN_API_KEY');
const typesenseSearchApiKey = defineSecret('TYPESENSE_SEARCH_API_KEY');

const client = new Typesense.Client({
'nodes': [{
'host': 'xxx.a1.typesense.net', // where xxx is the ClusterID of your Typesense Cloud cluster
'port': '443',
'protocol': 'https'
}],
'apiKey': TYPESENSE_ADMIN_API_KEY,
'connectionTimeoutSeconds': 2
let client;
onInit(() => {
client = new Typesense.Client({
'nodes': [{
'host': 'xxx.a1.typesense.net', // where xxx is the ClusterID of your Typesense Cloud cluster
'port': '443',
'protocol': 'https'
}],
'apiKey': typesenseAdminApiKey.value(),
'connectionTimeoutSeconds': 2
});
});
// [END init_typesense]

// [START create_typesense_collections]
async function createTypesenseCollections() {
// Every 'collection' in Typesense needs a schema. A collection only
// needs to be created one time before you index your first document.
//
// Alternatively, use auto schema detection:
// https://typesense.org/docs/latest/api/collections.html#with-auto-schema-detection
const notesCollection = {
'name': 'notes',
'fields': [
{'name': 'id', 'type': 'string'},
{'name': 'owner', 'type': 'string' },
{'name': 'text', 'type': 'string' }
]
};

await client.collections().create(notesCollection);
}
// [END create_typesense_collections]

// [START update_index_function_typesense]
// Update the search index every time a blog post is written.
exports.onNoteWritten = functions.firestore.document('notes/{noteId}').onWrite(async (snap, context) => {
exports.onNoteWritten = functions.runWith({secrets: [typesenseAdminApiKey]}).firestore.document('notes/{noteId}').onWrite(async (snap, context) => {
// Use the 'nodeId' path segment as the identifier for Typesense
const id = context.params.noteId;

Expand All @@ -78,7 +63,7 @@ exports.onNoteWritten = functions.firestore.document('notes/{noteId}').onWrite(a
// [END update_index_function_typesense]

// [START api_key_function_typesense]
exports.getScopedApiKey = functions.https.onCall(async (data, context) => {
exports.getScopedApiKey = functions.runWith({secrets: [typesenseAdminApiKey, typesenseSearchApiKey]}).https.onCall(async (data, context) => {
// Ensure that the user is authenticated with Firebase Auth
if (!(context.auth && context.auth.uid)) {
throw new functions.https.HttpsError('permission-denied', 'Must be signed in!');
Expand All @@ -87,7 +72,7 @@ exports.getScopedApiKey = functions.https.onCall(async (data, context) => {
// Generate a scoped API key which allows the user to search ONLY
// documents which belong to them (based on the 'owner' field).
const scopedApiKey = client.keys().generateScopedSearchKey(
TYPESENSE_SEARCH_API_KEY,
typesenseSearchApiKey.value(),
{
'filter_by': `owner:${context.auth.uid}`
}
Expand Down
3 changes: 2 additions & 1 deletion Node-1st-gen/fulltext-search/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ Enable Billing on your Firebase project by switching to the Blaze plan. You need
Set the `algolia.app_id` and `algolia.api_key` Google Cloud environment variables to match the Algolia application ID and API key of your account. For this use:

```bash
firebase functions:config:set algolia.app_id="myAlgoliaAppId" algolia.api_key="myAlgoliaApiKey"
firebase functions:secrets:set ALGOLIA_APP_ID
firebase functions:secrets:set ALGOLIA_API_KEY
```
16 changes: 12 additions & 4 deletions Node-1st-gen/fulltext-search/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@
'use strict';

const functions = require('firebase-functions/v1');
const {onInit} = require('firebase-functions/v1/init');
const {defineSecret} = require('firebase-functions/params');
const admin = require('firebase-admin');
admin.initializeApp();

// Authenticate to Algolia Database.
// TODO: Make sure you configure the `algolia.app_id` and `algolia.api_key` Google Cloud environment variables.
// TODO: Make sure you configure the `ALGOLIA_APP_ID` and `ALGOLIA_API_KEY` secrets.
const algoliasearch = require('algoliasearch').default;
const client = algoliasearch(functions.config().algolia.app_id, functions.config().algolia.api_key);
const algoliaAppId = defineSecret('ALGOLIA_APP_ID');
const algoliaApiKey = defineSecret('ALGOLIA_API_KEY');

let client;
onInit(() => {
client = algoliasearch(algoliaAppId.value(), algoliaApiKey.value());
});

// Name fo the algolia index for Blog posts content.
const ALGOLIA_POSTS_INDEX_NAME = 'blogposts';

// Updates the search index when new blog entries are created or updated.
exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite(
exports.indexentry = functions.runWith({secrets: [algoliaAppId, algoliaApiKey]}).database.ref('/blog-posts/{blogid}/text').onWrite(
async (data, context) => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
const firebaseObject = {
Expand All @@ -42,7 +50,7 @@ exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite

// Starts a search query whenever a query is requested (by adding one to the `/search/queries`
// element. Search results are then written under `/search/results`.
exports.searchentry = functions.database.ref('/search/queries/{queryid}').onCreate(
exports.searchentry = functions.runWith({secrets: [algoliaAppId, algoliaApiKey]}).database.ref('/search/queries/{queryid}').onCreate(
async (snap, context) => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);

Expand Down
3 changes: 2 additions & 1 deletion Node-1st-gen/github-to-slack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ To test this integration:
- [Add an **Incoming Webhook**](https://my.slack.com/services/new/incoming-webhook/) to your Slack channel and take note of the **Webhook URL**.
- Set the `slack.webhook_url` and `github.secret` Google Cloud environment variables to match the email and password of the Gmail account used to send emails. For this use:
```bash
firebase functions:config:set slack.webhook_url="https://hooks.slack.com/services/..." github.secret="A_SECRET_YOU_DEFINED_WHEN_SETTING_UP_THE_GITHUB_WEBHOOK"
firebase functions:secrets:set SLACK_WEBHOOK_URL
firebase functions:secrets:set GITHUB_SECRET
```
- Deploy your project using `firebase deploy`
- Push a commit to your GitHub repo
Loading