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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Firebase Extensions

This repository contains the source for Firebase Extensions. Created and tested by Firebase, these official Firebase extensions are reliable and secure. To learn more about Firebase Extensions, including how to install them in your Firebase projects, visit the [Firebase documentation](https://firebase.google.com/docs/extensions).
This repository contains the source for Firebase Extensions. Created and tested by Firebase, these official Firebase extensions are reliable and secure.

To learn more about Firebase Extensions, including how to install them in your Firebase projects, visit the [Firebase documentation](https://firebase.google.com/docs/extensions).

Each directory in this repo contains the source code for the extension and a README to explain how the extension works, including information about the APIs enabled, resources created, and the access granted to the extension.

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@firebaseextensions/fs-bq-schema-views",
"version": "0.4.10",
"version": "0.4.11",
"description": "Generate strongly-typed BigQuery Views based on raw JSON",
"main": "./lib/index.js",
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions firestore-bigquery-export/scripts/import/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion firestore-bigquery-export/scripts/import/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@firebaseextensions/fs-bq-import-collection",
"version": "0.1.23",
"version": "0.1.24",
"description": "Import a Firestore Collection into a BigQuery Changelog Table",
"main": "./lib/index.js",
"repository": {
Expand Down
6 changes: 6 additions & 0 deletions firestore-send-email/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Version 0.2.2

fix: fix validation of payloads

docs: add documentation on how to use dynamic templates with SendGrid

## Version 0.2.1

fix: return info on sendgrid messages
Expand Down
23 changes: 23 additions & 0 deletions firestore-send-email/POSTINSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,29 @@ Add this document to the Firestore mail collection to send categorized emails.

For more details, see the [SendGrid Categories documentation](https://docs.sendgrid.com/ui/sending-email/categories).

#### Firestore-Send-Email: SendGrid Dynamic Templates

When using SendGrid, you can use SendGrid Dynamic Templates to create and send templated emails.

## Example JSON representation of Firestore document for a Dynamic Template:
```json
{
"to": ["example@example.com"],
"sendGrid": {
"templateId": "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"dynamicTemplateData": {
"name": "John Doe",
"company": "Example Corp",
"position": "Developer"
}
}
}
```

Add this document to the Firestore mail collection to send an email using a SendGrid Dynamic Template. The `templateId` is required and should be your SendGrid Dynamic Template ID (always starts with 'd-'). The `dynamicTemplateData` object contains the variables that will be used in your template.

For more details, see the [SendGrid Dynamic Templates documentation](https://docs.sendgrid.com/ui/sending-email/how-to-send-an-email-with-dynamic-templates).

#### Understanding SendGrid Email IDs

When an email is sent successfully, the extension tracks two different IDs in the delivery information:
Expand Down
25 changes: 24 additions & 1 deletion firestore-send-email/PREINSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ Add this document to the Firestore mail collection to send categorized emails.

For more details, see the [SendGrid Categories documentation](https://docs.sendgrid.com/ui/sending-email/categories).

#### Firestore-Send-Email: SendGrid Dynamic Templates

When using SendGrid, you can use SendGrid Dynamic Templates to create and send templated emails.

## Example JSON representation of Firestore document for a Dynamic Template:
```json
{
"to": ["example@example.com"],
"sendGrid": {
"templateId": "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // SendGrid Dynamic Template ID always starts with 'd-'
"dynamicTemplateData": {
"name": "John Doe",
"company": "Example Corp",
"position": "Developer"
}
}
}
```

Add this document to the Firestore mail collection to send an email using a SendGrid Dynamic Template. The `templateId` is required and should be your SendGrid Dynamic Template ID (always starts with 'd-'). The `dynamicTemplateData` object contains the variables that will be used in your template.

For more details, see the [SendGrid Dynamic Templates documentation](https://docs.sendgrid.com/ui/sending-email/how-to-send-an-email-with-dynamic-templates).

#### Setting Up OAuth2 Authentication

This section will help you set up OAuth2 authentication for the extension, using GCP (Gmail) as an example.
Expand Down Expand Up @@ -195,7 +218,7 @@ Detailed instructions for creating a TTL field can be found in the [Firestore TT
#### Billing
To install an extension, your project must be on the [Blaze (pay as you go) plan](https://firebase.google.com/pricing)

- This extension uses other Firebase and Google Cloud Platform services, which have associated charges if you exceed the services no-cost tier:
- This extension uses other Firebase and Google Cloud Platform services, which have associated charges if you exceed the service's no-cost tier:
- Cloud Firestore
- Cloud Functions (Node.js 10+ runtime. [See FAQs](https://firebase.google.com/support/faq#extensions-pricing))

Expand Down
25 changes: 24 additions & 1 deletion firestore-send-email/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ Add this document to the Firestore mail collection to send categorized emails.

For more details, see the [SendGrid Categories documentation](https://docs.sendgrid.com/ui/sending-email/categories).

#### Firestore-Send-Email: SendGrid Dynamic Templates

When using SendGrid, you can use SendGrid Dynamic Templates to create and send templated emails.

## Example JSON representation of Firestore document for a Dynamic Template:
```json
{
"to": ["example@example.com"],
"sendGrid": {
"templateId": "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // SendGrid Dynamic Template ID always starts with 'd-'
"dynamicTemplateData": {
"name": "John Doe",
"company": "Example Corp",
"position": "Developer"
}
}
}
```

Add this document to the Firestore mail collection to send an email using a SendGrid Dynamic Template. The `templateId` is required and should be your SendGrid Dynamic Template ID (always starts with 'd-'). The `dynamicTemplateData` object contains the variables that will be used in your template.

For more details, see the [SendGrid Dynamic Templates documentation](https://docs.sendgrid.com/ui/sending-email/how-to-send-an-email-with-dynamic-templates).

#### Setting Up OAuth2 Authentication

This section will help you set up OAuth2 authentication for the extension, using GCP (Gmail) as an example.
Expand Down Expand Up @@ -203,7 +226,7 @@ Detailed instructions for creating a TTL field can be found in the [Firestore TT
#### Billing
To install an extension, your project must be on the [Blaze (pay as you go) plan](https://firebase.google.com/pricing)

- This extension uses other Firebase and Google Cloud Platform services, which have associated charges if you exceed the services no-cost tier:
- This extension uses other Firebase and Google Cloud Platform services, which have associated charges if you exceed the service's no-cost tier:
- Cloud Firestore
- Cloud Functions (Node.js 10+ runtime. [See FAQs](https://firebase.google.com/support/faq#extensions-pricing))

Expand Down
2 changes: 1 addition & 1 deletion firestore-send-email/extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

name: firestore-send-email
version: 0.2.1
version: 0.2.2
specVersion: v1beta

displayName: Trigger Email from Firestore
Expand Down
145 changes: 145 additions & 0 deletions firestore-send-email/functions/__tests__/e2e/sendgrid.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// This test suite assumes local emulator is running the extension, with the following config:

// AUTH_TYPE=UsernamePassword
// DATABASE=(default)
// DATABASE_REGION=us-east1
// DEFAULT_FROM=<some-email>
// MAIL_COLLECTION=emailCollection
// OAUTH_PORT=465
// SMTP_CONNECTION_URI=smtps://apikey@smtp.sendgrid.net:465
// TEMPLATES_COLLECTION=emailTemplates
// TTL_EXPIRE_TYPE=never
// TTL_EXPIRE_VALUE=1

// set the TEST_EMAIL environment variable to the recipient email address for the test
const TEST_EMAIL = process.env.TEST_EMAIL || "test@example.com";

// and that the sendgrid api key is set as a secret for the emulator in a .secret.local file

import * as admin from "firebase-admin";

// Test data constants
const TEST_TEMPLATE = {
name: "test_template",
subject: "Test Subject",
text: `Hello {{userName}},

Thank you for your order:
{{orderText}}

Your order will be processed by {{doctorName}}.

Business Hours:
{{openingHours}}

Address:
{{address}}

Best regards,
The Team`,
html: `
<!DOCTYPE html>
<html>
<body>
<p>Hello {{userName}},</p>
<p>Thank you for your order: {{orderText}}</p>
<p>Your order will be processed by {{doctorName}}.</p>
<p>Business Hours: {{openingHours}}</p>
<p>Address: {{address}}</p>
<p>Best regards,<br>The Team</p>
</body>
</html>`,
};

const TEST_TEMPLATE_DATA = {
address: "123 Test Street, Test City",
doctorName: "Dr. Test",
openingHours: "Mon-Fri: 9:00-17:00",
orderText: "Test order items",
userName: "Test User",
};

const TEST_COLLECTIONS = ["emailCollection", "emailTemplates"] as const;

// Skip the entire suite if E2E_SENDGRID is not set to true
(process.env.E2E_SENDGRID === "true" ? describe : describe.skip)(
"SendGrid E2E Tests",
() => {
beforeAll(() => {
// Initialize with emulator settings
admin.initializeApp({
projectId: "dev-extensions-testing",
databaseURL: "http://localhost:8080?ns=dev-extensions-testing",
});

// Point Firestore to the emulator
process.env.FIRESTORE_EMULATOR_HOST = "localhost:8080";
});

beforeEach(async () => {
// Clear all data from the emulator
const db = admin.firestore();

for (const collection of TEST_COLLECTIONS) {
const snapshot = await db.collection(collection).get();
const batch = db.batch();

snapshot.docs.forEach((doc) => {
batch.delete(doc.ref);
});

await batch.commit();
}

// Create the email template
await db.collection("emailTemplates").doc(TEST_TEMPLATE.name).set({
subject: TEST_TEMPLATE.subject,
text: TEST_TEMPLATE.text,
html: TEST_TEMPLATE.html,
});
});

test("should process a template-based email document", async () => {
const db = admin.firestore();

const testData = {
message: {
attachments: [],
html: null,
text: null,
subject: TEST_TEMPLATE.subject,
},
template: {
data: TEST_TEMPLATE_DATA,
name: TEST_TEMPLATE.name,
},
to: TEST_EMAIL,
};

// Write the document to the emulator
const docRef = db.collection("emailCollection").doc("test-doc");
await docRef.set(testData);

// Wait a bit for the function to process
await new Promise((resolve) => setTimeout(resolve, 2000));

// Verify the document was updated
const doc = await docRef.get();
const updatedData = doc.data();

// Assert the delivery state was updated to SUCCESS
console.log("updatedData", updatedData);
expect(updatedData?.delivery.state).toBe("SUCCESS");
expect(updatedData?.delivery.attempts).toBe(1);
expect(updatedData?.delivery.endTime).toBeDefined();
expect(updatedData?.delivery.error).toBeNull();

// Verify SendGrid specific info
expect(updatedData?.delivery.info).toBeDefined();
expect(updatedData?.delivery.info?.messageId).toBeDefined();
expect(updatedData?.delivery.info?.accepted).toContain(TEST_EMAIL);
expect(updatedData?.delivery.info?.rejected).toEqual([]);
expect(updatedData?.delivery.info?.pending).toEqual([]);
});
}
);
Loading
Loading