Skip to content

Commit

Permalink
Merge pull request #24 from microsoft/fix/configuration_issues
Browse files Browse the repository at this point in the history
Configuration Updates
  • Loading branch information
darthtrevino authored Aug 26, 2021
2 parents 9c99afb + 5fa740f commit 0bafd5f
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 78 deletions.
38 changes: 33 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,39 @@ The following branch naming patterns are utilized for different kinds of efforts
- Testing: `test/*`
- Refactoring: `refactor/*`

## Operations
## Operations & Deployment

### Configuration
The [GitHub Actions CI](.github/workflows/ci.yml) workflow is used to automate the deployment of the app in accordance with the branching strategy described above. The infrastructure required for an instance of the application is:

1. A MongoDB compatible database. We use CosmosDB with MongoDB driver.
2. A NodeJS web-server environment for the [GraphQL API](packages/api).
3. A static website deployment (Azure Blob Storage/S3) for the [web application](packages/webapp). This may be CDN-hosted or self-hosted in static storage.
4. A SendGrid account for sending automated emails (e.g. password reset emails).
5. (_optional_) A Firebase account for In-App Notifications.

### External Dependencies
### Configuration

- Firebase
- Sendgrid
The application uses the [config](npm.im/config) package to manage configuration settings per hosted environment. The following environment variables may be defined to override configuration settings:

- API [environment variables](packages/api/config/custom-environment-variables.md)

- **DB_CONNECTION_STRING** (_required_): The MongoDB connection string for the database.
- **JWT_SECRET** (_strongly recommended_): A secret, random string used for salting JWT tokens.
- **SENDGRID_API_KEY** (_required for email_): The SendGrid API key.
- **EMAIL_FROM** (_required for email_): The email address used for sending automated emails.
- **CONTACT_US_EMAIL** (_required for email_): The email address used for customer support.
- **PORT** (_optional_): the port the application is running on. This is provided by default from the Azure App Service runtime.
- **FIREBASE_AUTH_URI** (_optional_): The Firebase Auth URI for the Firebase account.
- **FIREBASE_TOKEN_URI** (_optional_): The Firebase Token URI for the Firebase account.
- **FIREBASE_AUTH_PROVIDER_X509_CERT_URL** (_optional_): The Firebase Auth Provider X509 Cert URL for the Firebase account.
- **FIREBASE_TYPE** (_optional_): The Firebase type for the Firebase account.
- **FIREBASE_PROJECT_ID** (_optional_): The Firebase project ID for the Firebase account.
- **FIREBASE_PRIVATE_KEY_ID** (_optional_): The Firebase private key ID for the Firebase account.
- **FIREBASE_PRIVATE_KEY** (_optional_): The Firebase private key for the Firebase account.
- **FIREBASE_CLIENT_EMAIL** (_optional_): The Firebase client email for the Firebase account.
- **FIREBASE_CLIENT_ID** (_optional_): The Firebase client ID for the Firebase account.
- **FIREBASE_CLIENT_X509_CERT_URL** (_optional_): The Firebase client X509 Cert URL for the Firebase account.

- Web App [environment variables](packages/webapp/config/custom-environment-variables.md)
- **API_URL** (_required_): The URL of the GraphQL API this webapp will communicate with.
- **SOCKET_URL** (_required_): The URL of the sockets API this webapp will communicate with.
21 changes: 13 additions & 8 deletions packages/api/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@
"security": {
"jwtSecret": "JWT_SECRET"
},
"smtp": {
"port": "SMTP_PORT",
"host": "SMTP_HOST",
"auth": {
"user": "SMTP_USER",
"pass": "SMTP_PASSWORD"
}
},
"email": {
"sendgridApiKey": "SENDGRID_API_KEY",
"from": "EMAIL_FROM",
"contactUs": "CONTACT_US_EMAIL"
},
"firebase": {
"auth_uri": "FIREBASE_AUTH_URI",
"token_uri": "FIREBASE_TOKEN_URI",
"auth_provider_x509_cert_url": "FIREBASE_AUTH_PROVIDER_X509_CERT_URL",
"type": "FIREBASE_TYPE",
"project_id": "FIREBASE_PROJECT_ID",
"private_key_id": "FIREBASE_PRIVATE_KEY_ID",
"private_key": "FIREBASE_PRIVATE_KEY",
"client_email": "FIREBASE_CLIENT_EMAIL",
"client_id": "FIREBASE_CLIENT_ID",
"client_x509_cert_url": "FIREBASE_CLIENT_X509_CERT_URL"
}
}
23 changes: 13 additions & 10 deletions packages/api/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,21 @@
"security": {
"jwtSecret": "greenlight-development"
},
"smtp": {
"pool": true,
"host": null,
"port": 465,
"secure": true,
"auth": {
"user": null,
"pass": null
}
},
"email": {
"sendgridApiKey": null,
"from": null,
"contactUs": null
},
"firebase": {
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"type": "service_account",
"project_id": null,
"private_key_id": null,
"private_key": null,
"client_email": null,
"client_id": null,
"client_x509_cert_url": null
}
}
12 changes: 0 additions & 12 deletions packages/api/config/firebase-admin-sdk.json

This file was deleted.

4 changes: 2 additions & 2 deletions packages/api/src/components/AppContextProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ export class AppContextProvider implements AsyncProvider<BuiltAppContext> {
const userTokenCollection = new UserTokenCollection(conn.userTokensCollection)
const orgCollection = new OrganizationCollection(conn.orgsCollection)
const localization = new Localization()
const notify = new Notifications()
const notify = new Notifications(config)
const mailer = nodemailer.createTransport(
sgTransport({
auth: {
api_key: config.smtpDetails.auth.pass
api_key: config.sendgridApiKey
}
})
)
Expand Down
18 changes: 8 additions & 10 deletions packages/api/src/components/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,8 @@ export class Configuration {
if (this.jwtTokenSecret == null) {
throw new Error('JWT_SECRET must be defined')
}
if (!this.smtpDetails.auth.user) {
console.warn('SMTP_USER is not set, mail disabled')
}
if (!this.smtpDetails.auth.pass) {
console.warn('SMTP_PASSWORD is not set, mail disabled')
}
if (!this.smtpDetails.host) {
console.warn('SMTP_HOST is not set, mail disabled')
if (!this.sendgridApiKey) {
console.warn('SENDGRID_API_KEY is not set, mail disabled')
}
if (!this.defaultFromAddress) {
console.warn('EMAIL_FROM is not set, mail disabled')
Expand Down Expand Up @@ -95,11 +89,15 @@ export class Configuration {
return this.c.get<string>('security.jwtSecret')
}

public get smtpDetails(): any {
return this.c.get<any>('smtp')
public get sendgridApiKey(): any {
return this.c.get<string>('email.sendgridApiKey')
}

public get defaultFromAddress(): string {
return this.c.get<string>('email.from')
}

public get firebaseSettings(): any {
return this.c.get<any>('firebase')
}
}
60 changes: 38 additions & 22 deletions packages/api/src/components/Notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { Configuration } from './Configuration'
import * as admin from 'firebase-admin'
import serviceAccount from '../../config/firebase-admin-sdk.json'
import {
initializeApp as fbInitializeApp,
credential as fbCredential,
ServiceAccount as FBServiceAccount,
messaging as fbMessaging,
app as fbApp
} from 'firebase-admin'

export interface MessageOptions {
token: string
Expand All @@ -18,14 +23,17 @@ export interface NotificationOptions {
}

export class Notifications {
#config: Configuration | undefined
#fbAdmin: admin.app.App
#config: Configuration
#fbAdmin: fbApp.App | null

public constructor(config?: Configuration) {
public constructor(config: Configuration) {
this.#config = config
this.#fbAdmin = admin.initializeApp({
credential: admin.credential.cert(serviceAccount as admin.ServiceAccount)
})
const isEnabled = Boolean(config.firebaseSettings.private_key)
this.#fbAdmin = isEnabled
? fbInitializeApp({
credential: fbCredential.cert(config.firebaseSettings as FBServiceAccount)
})
: null
}

/**
Expand All @@ -34,28 +42,36 @@ export class Notifications {
*/
public async sendMessage(
messageOptions: MessageOptions
): Promise<admin.messaging.MessagingDevicesResponse> {
const sendResult = await this.#fbAdmin.messaging().sendToDevice(messageOptions.token, {
notification: messageOptions.notification
} as admin.messaging.MessagingPayload)
): Promise<fbMessaging.MessagingDevicesResponse | null> {
if (this.#fbAdmin) {
const sendResult = await this.#fbAdmin!.messaging().sendToDevice(messageOptions.token, {
notification: messageOptions.notification
} as fbMessaging.MessagingPayload)

return sendResult
return sendResult
} else {
return null
}
}

/**
* Send a notification related to being assigned a request by a user
*/
public async assignedRequest(
fcmToken: string
): Promise<admin.messaging.MessagingDevicesResponse> {
const sendResult = await this.sendMessage({
token: fcmToken,
notification: {
title: 'A client needs your help!',
body: 'Go to the dashboard to view this request'
}
})
): Promise<fbMessaging.MessagingDevicesResponse | null> {
if (this.#fbAdmin) {
const sendResult = await this.sendMessage({
token: fcmToken,
notification: {
title: 'A client needs your help!',
body: 'Go to the dashboard to view this request'
}
})

return sendResult
return sendResult
} else {
return null
}
}
}
5 changes: 1 addition & 4 deletions packages/api/src/utils/isSendMailConfigured.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,5 @@
import { Configuration } from '~components'

export function isSendMailConfigured(config: Configuration): boolean {
const mailConfig = config.smtpDetails
return (
!!mailConfig?.host && !!mailConfig?.port && !!mailConfig?.auth?.user && !!mailConfig?.auth?.pass
)
return !!config.sendgridApiKey
}
5 changes: 0 additions & 5 deletions packages/webapp/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
{
"server": {
"port": "PORT",
"sslToken": "SSL_TOKEN",
"sslVerificationMode": "SSL_VERIFICATION_MODE"
},
"api": {
"url": "API_URL",
"socketUrl": "API_SOCKET_URL"
Expand Down

0 comments on commit 0bafd5f

Please sign in to comment.