Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(firestore-send-email): migrate to v2 cloud function #2359

Draft
wants to merge 11 commits into
base: next
Choose a base branch
from
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.0

feat: use v2 firestore trigger

feat: allow non-(default) firestore instances

## Version 0.1.37

feat: add support for OAuth2 authentication
Expand Down
2 changes: 1 addition & 1 deletion firestore-send-email/POSTINSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

You can test out this extension right away!

1. Go to your [Cloud Firestore dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/firestore/data) in the Firebase console.
1. Go to your [Cloud Firestore dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/firestore/data) in the Firebase console. Note that, if you have configured a non-default firestore database, you may have to view it via the [Google Cloud Console](https://console.cloud.google.com/firestore/databases/${param:DATABASE}).

1. If it doesn't already exist, create the collection you specified during installation: `${param:MAIL_COLLECTION}`.

Expand Down
10 changes: 8 additions & 2 deletions firestore-send-email/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ You can find more information about this extension in the following articles:

**Configuration Parameters:**

* Firestore Instance ID: The Firestore database to use. Use "(default)" for the default database. You can view your available Firestore databases at [https://console.cloud.google.com/firestore/databases](https://console.cloud.google.com/firestore/databases).


* Firestore Instance Location: Where is the Firestore database located? You can check your current database location at [https://console.cloud.google.com/firestore/databases](https://console.cloud.google.com/firestore/databases).


* Authentication Type: The authentication type to be used for the SMTP server (e.g., OAuth2, Username & Password.

* SMTP connection URI: A URI representing an SMTP server this extension can use to deliver email. Note that port 25 is blocked by Google Cloud Platform, so we recommend using port 587 for SMTP connections. If you're using the SMTPS protocol, we recommend using port 465. In order to keep passwords secure, it is recommended to omit the password from the connection string while using the `SMTP Password` field for entering secrets and passwords. Passwords and secrets should now be included in `SMTP password` field.
Expand Down Expand Up @@ -263,9 +269,9 @@ password)



**Cloud Functions:**
**Other Resources**:

* **processQueue:** Processes document changes in the specified Cloud Firestore collection, delivers emails, and updates the document with delivery status information.
* processQueue (firebaseextensions.v1beta.v2function)



Expand Down
149 changes: 144 additions & 5 deletions 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.1.37
version: 0.2.0
specVersion: v1beta

displayName: Trigger Email from Firestore
Expand Down Expand Up @@ -47,18 +47,157 @@ roles:

resources:
- name: processQueue
type: firebaseextensions.v1beta.function
type: firebaseextensions.v1beta.v2function
description:
Processes document changes in the specified Cloud Firestore collection,
delivers emails, and updates the document with delivery status
information.
properties:
runtime: nodejs20
sourceDirectory: functions
buildConfig:
runtime: nodejs22
serviceConfig:
timeoutSeconds: 120
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${param:PROJECT_ID}/databases/(default)/documents/${param:MAIL_COLLECTION}/{id}
eventType: google.cloud.firestore.document.v1.written
triggerRegion: ${DATABASE_REGION}
eventFilters:
- attribute: database
value: ${DATABASE}
- attribute: document
value: ${MAIL_COLLECTION}/{documentId}
operator: match-path-pattern

params:
- param: DATABASE
label: Firestore Instance ID
description: >
The Firestore database to use. Use "(default)" for the default database.
You can view your available Firestore databases at
[https://console.cloud.google.com/firestore/databases](https://console.cloud.google.com/firestore/databases).
example: (default)
default: (default)
required: true

- param: DATABASE_REGION
label: Firestore Instance Location
description: >
Where is the Firestore database located? You can check your current
database location at
[https://console.cloud.google.com/firestore/databases](https://console.cloud.google.com/firestore/databases).
type: select
options:
# Multi-region locations
- label: Europe (multi-regional, eur3)
value: eur3
- label: United States (multi-regional, nam5)
value: nam5
- label: Europe (multi-regional)
value: eu
- label: United States (multi-regional)
value: us

# North America
- label: Iowa (us-central1)
value: us-central1
- label: Oregon (us-west1)
value: us-west1
- label: Los Angeles (us-west2)
value: us-west2
- label: Salt Lake City (us-west3)
value: us-west3
- label: Las Vegas (us-west4)
value: us-west4
- label: South Carolina (us-east1)
value: us-east1
- label: Northern Virginia (us-east4)
value: us-east4
- label: Columbus (us-east5)
value: us-east5
- label: Dallas (us-south1)
value: us-south1
- label: Montreal (northamerica-northeast1)
value: northamerica-northeast1
- label: Toronto (northamerica-northeast2)
value: northamerica-northeast2
- label: Queretaro (northamerica-south1)
value: northamerica-south1

# South America
- label: Sao Paulo (southamerica-east1)
value: southamerica-east1
- label: Santiago (southamerica-west1)
value: southamerica-west1

# Europe
- label: Belgium (europe-west1)
value: europe-west1
- label: London (europe-west2)
value: europe-west2
- label: Frankfurt (europe-west3)
value: europe-west3
- label: Netherlands (europe-west4)
value: europe-west4
- label: Zurich (europe-west6)
value: europe-west6
- label: Milan (europe-west8)
value: europe-west8
- label: Paris (europe-west9)
value: europe-west9
- label: Berlin (europe-west10)
value: europe-west10
- label: Turin (europe-west12)
value: europe-west12
- label: Madrid (europe-southwest1)
value: europe-southwest1
- label: Finland (europe-north1)
value: europe-north1
- label: Stockholm (europe-north2)
value: europe-north2
- label: Warsaw (europe-central2)
value: europe-central2

# Middle East
- label: Doha (me-central1)
value: me-central1
- label: Dammam (me-central2)
value: me-central2
- label: Tel Aviv (me-west1)
value: me-west1

# Asia
- label: Mumbai (asia-south1)
value: asia-south1
- label: Delhi (asia-south2)
value: asia-south2
- label: Singapore (asia-southeast1)
value: asia-southeast1
- label: Jakarta (asia-southeast2)
value: asia-southeast2
- label: Taiwan (asia-east1)
value: asia-east1
- label: Hong Kong (asia-east2)
value: asia-east2
- label: Tokyo (asia-northeast1)
value: asia-northeast1
- label: Osaka (asia-northeast2)
value: asia-northeast2
- label: Seoul (asia-northeast3)
value: asia-northeast3

# Australia
- label: Sydney (australia-southeast1)
value: australia-southeast1
- label: Melbourne (australia-southeast2)
value: australia-southeast2

# Africa
- label: Johannesburg (africa-south1)
value: africa-south1
default: us
required: true
immutable: true

- param: AUTH_TYPE
label: Authentication Type
description: >-
Expand Down
4 changes: 4 additions & 0 deletions firestore-send-email/functions/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ functionsTestInit();

const environment = {
LOCATION: "us-central1",
DATABASE: "fake-database",
DATABASE_REGION: "us-central1",
TEMPLATES_COLLECTION: "templates",
MAIL_COLLECTION: "mail",
SMTP_CONNECTION_URI:
Expand Down Expand Up @@ -41,6 +43,8 @@ describe("extensions config", () => {
test("config loaded from environment variables", () => {
const testConfig: Config = {
location: process.env.LOCATION,
database: process.env.DATABASE,
databaseRegion: process.env.DATABASE_REGION,
mailCollection: process.env.MAIL_COLLECTION,
smtpConnectionUri: process.env.SMTP_CONNECTION_URI,
smtpPassword: process.env.SMTP_PASSWORD,
Expand Down
28 changes: 28 additions & 0 deletions firestore-send-email/functions/__tests__/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const regex = new RegExp(
describe("setSmtpCredentials function", () => {
test("return smtpServerDomain credentials with new password", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtps://[email protected]:[email protected]:465",
smtpPassword: "fakepassword",
Expand All @@ -35,6 +37,8 @@ describe("setSmtpCredentials function", () => {

test("return smtpServerDomain credentials with old password", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtps://[email protected]:[email protected]:465",
location: "",
Expand All @@ -56,6 +60,8 @@ describe("setSmtpCredentials function", () => {

test("return smtpConnectionUri credentials without any password", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri: "smtps://[email protected]@smtp.gmail.com:465",
location: "",
mailCollection: "",
Expand All @@ -76,6 +82,8 @@ describe("setSmtpCredentials function", () => {

test("return smtpConnectionUri credentials without any password and username", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri: "smtp://smtp.gmail.com:465",
location: "",
mailCollection: "",
Expand All @@ -95,6 +103,8 @@ describe("setSmtpCredentials function", () => {

test("return smtpConnectionUri credentials with query params", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtp://[email protected]:[email protected]:465?pool=true&service=gmail",
location: "",
Expand All @@ -118,6 +128,8 @@ describe("setSmtpCredentials function", () => {

test("return valid smtpConnectionUri credentials with valid special chars in password", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtp://[email protected]@smtp.gmail.com:465?pool=true&service=gmail",
smtpPassword: "4,h?dhuNTbv9zMrP4&7&7%*3",
Expand All @@ -142,6 +154,8 @@ describe("setSmtpCredentials function", () => {

test("return valid smtpConnectionUri credentials with valid special chars in connectionUri password", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtp://[email protected]:4,hdhuNTbv9zMrP4&7&7%*[email protected]:465?pool=true&service=gmail",
location: "",
Expand All @@ -166,6 +180,8 @@ describe("setSmtpCredentials function", () => {

test("throw error for invalid smtpConnectionUri", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtp://[email protected]:4,h?dhuNTbv9zMrP4&7&7%*[email protected]:465?pool=true&service=gmail",
location: "",
Expand All @@ -184,6 +200,8 @@ describe("setSmtpCredentials function", () => {
describe("isSendGrid function", () => {
test("return true for SendGrid SMTP URI", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri: "smtps://[email protected]:465",
location: "",
mailCollection: "",
Expand All @@ -196,6 +214,8 @@ describe("isSendGrid function", () => {

test("return false for non-SendGrid SMTP URI", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtps://[email protected]:[email protected]:465",
location: "",
Expand All @@ -210,6 +230,8 @@ describe("isSendGrid function", () => {

test("return invalid smtpConnectionUri credentials with invalid separator", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtp://[email protected]:4,h?dhuNTbv9zMrP4&7&7%*3:smtp.gmail.com:465?pool=true&service=gmail",
location: "",
Expand All @@ -224,6 +246,8 @@ test("return invalid smtpConnectionUri credentials with invalid separator", () =

test("correctly detects SendGrid SMTP URI", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri: "smtps://[email protected]:465",
location: "",
mailCollection: "",
Expand All @@ -234,6 +258,8 @@ test("correctly detects SendGrid SMTP URI", () => {
expect(isSendGrid(config)).toBe(true);

const invalidConfig: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri: "smtps://[email protected]:465",
location: "",
mailCollection: "",
Expand All @@ -246,6 +272,8 @@ test("correctly detects SendGrid SMTP URI", () => {

test("correctly uses oAuth credentials when provided", () => {
const config: Config = {
database: "fake-database",
databaseRegion: "us-central1",
smtpConnectionUri:
"smtps://[email protected]:[email protected]:465",
location: "",
Expand Down
Loading
Loading