-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Scott Prue
committed
Sep 14, 2019
1 parent
2005068
commit 5ab94b2
Showing
14 changed files
with
401 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import * as functions from 'firebase-functions' | ||
import { getAppFromServiceAccount } from '../utils/serviceAccounts' | ||
import { dataArrayFromSnap } from '../utils/firestore' | ||
|
||
/** | ||
* @param {Object} data - Data passed into httpsCallable by client | ||
* @param {Object} context - Cloud function context | ||
* @param {Object} context.auth - Cloud function context | ||
* @param {Object} context.auth.uid - UID of user that made the request | ||
* @param {Object} context.auth.name - Name of user that made the request | ||
*/ | ||
export async function environmentDataViewerRequest(data, context) { | ||
console.log('Environment data viewer request:', data) | ||
const { projectId } = data | ||
// TODO: Confirm user has rights to this environment/serviceAccount | ||
// Get app from service account (loaded from project) | ||
const app = await getAppFromServiceAccount(data, { projectId }) | ||
// TODO: Make this dynamice to a number of resources | ||
const topLevelResource = app[data.resource]() // database/firestore/etc | ||
// TODO: Support multiple levels of query | ||
const query = | ||
data.resource === 'firestore' | ||
? topLevelResource.collection('projects').get() | ||
: topLevelResource.ref('projects').once('value') | ||
const dataSnap = await query | ||
const results = dataArrayFromSnap(dataSnap) | ||
return results | ||
} | ||
|
||
/** | ||
* @name environmentDataViewer | ||
* Cloud Function triggered by HTTP request | ||
* @type {functions.CloudFunction} | ||
*/ | ||
export default functions.https.onCall(environmentDataViewerRequest) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { to } from 'utils/async' | ||
|
||
describe('environmentDataViewer HTTPS Callable Cloud Function', () => { | ||
let environmentDataViewer | ||
let configStub | ||
let adminInitStub | ||
let functions | ||
let admin | ||
|
||
before(() => { | ||
/* eslint-disable global-require */ | ||
admin = require('firebase-admin') | ||
// Stub Firebase's admin.initializeApp | ||
adminInitStub = sinon.stub(admin, 'initializeApp') | ||
// Stub Firebase's functions.config() | ||
functions = require('firebase-functions') | ||
configStub = sinon.stub(functions, 'config').returns({ | ||
firebase: { | ||
databaseURL: 'https://not-a-project.firebaseio.com', | ||
storageBucket: 'not-a-project.appspot.com', | ||
projectId: 'not-a-project.appspot', | ||
messagingSenderId: '823357791673' | ||
} | ||
// Stub any other config values needed by your functions here | ||
}) | ||
environmentDataViewer = require(`./index`).environmentDataViewerRequest | ||
/* eslint-enable global-require */ | ||
}) | ||
|
||
after(() => { | ||
// Restoring our stubs to the original methods. | ||
configStub.restore() | ||
adminInitStub.restore() | ||
}) | ||
|
||
it('responds with hello message when sent an empty request', async () => { | ||
const data = {} | ||
const context = {} | ||
// Invoke request handler with fake data + context objects | ||
const [err, response] = await to(environmentDataViewer(data, context)) | ||
// Confirm no error is thrown | ||
expect(err).to.not.exist | ||
// Confirm response contains message | ||
expect(response).to.have.property('message', 'Hello World') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
src/routes/Project/routes/DataViewer/components/DataViewerPage/DataViewerPage.enhancer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import PropTypes from 'prop-types' | ||
import { get } from 'lodash' | ||
import { compose } from 'redux' | ||
import { connect } from 'react-redux' | ||
import firestoreConnect from 'react-redux-firebase/lib/firestoreConnect' | ||
import { withStyles } from '@material-ui/core/styles' | ||
import styles from './DataViewerPage.styles' | ||
// import { formValueSelector } from 'redux-form' | ||
// import { formNames } from 'constants' | ||
import { withHandlers, setPropTypes } from 'recompose' | ||
import firebase from 'firebase/app' | ||
import withNotifications from 'modules/notification/components/withNotifications' | ||
|
||
export default compose( | ||
withNotifications, | ||
// Proptypes for props used in HOCs | ||
setPropTypes({ | ||
params: PropTypes.shape({ | ||
projectId: PropTypes.string.isRequired | ||
}) | ||
}), | ||
// create listener for dataViewer, results go into redux | ||
firestoreConnect([{ collection: 'dataViewer' }]), | ||
// map redux state to props | ||
// Map redux state to props | ||
connect((state, { params }) => { | ||
const { | ||
firebase, | ||
firestore: { data, ordered } | ||
} = state | ||
// const formSelector = formValueSelector(formNames.actionRunner) | ||
const environmentsById = get(data, `environments-${params.projectId}`) | ||
return { | ||
uid: firebase.auth.uid, | ||
projectId: params.projectId, | ||
project: get(data, `projects.${params.projectId}`), | ||
environments: get(ordered, `environments-${params.projectId}`), | ||
environmentsById | ||
} | ||
}), | ||
withHandlers({ | ||
getData: ({ showSuccess, showError, projectId }) => formData => { | ||
return firebase | ||
.functions() | ||
.httpsCallable('environmentDataViewer')({ projectId, ...formData }) | ||
.then(() => { | ||
showSuccess('Data loaded') | ||
}) | ||
.catch(err => { | ||
showError('Error loading data') | ||
return Promise.reject(err) | ||
}) | ||
} | ||
}), | ||
withStyles(styles) | ||
) |
19 changes: 19 additions & 0 deletions
19
src/routes/Project/routes/DataViewer/components/DataViewerPage/DataViewerPage.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import DataViewerSetupForm from '../DataViewerSetupForm' | ||
|
||
function DataViewerPage({ classes, projectId, getData }) { | ||
return ( | ||
<div className={classes.container}> | ||
<DataViewerSetupForm projectId={projectId} onSubmit={getData} /> | ||
</div> | ||
) | ||
} | ||
|
||
DataViewerPage.propTypes = { | ||
classes: PropTypes.object.isRequired, // from enhancer (withStyles) | ||
getData: PropTypes.func.isRequired, // from enhancer (withHandlers) | ||
projectId: PropTypes.string.isRequired // from react-router | ||
} | ||
|
||
export default DataViewerPage |
5 changes: 5 additions & 0 deletions
5
src/routes/Project/routes/DataViewer/components/DataViewerPage/DataViewerPage.styles.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export default theme => ({ | ||
root: { | ||
// style code | ||
} | ||
}) |
4 changes: 4 additions & 0 deletions
4
src/routes/Project/routes/DataViewer/components/DataViewerPage/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import DataViewerPage from './DataViewerPage' | ||
import enhance from './DataViewerPage.enhancer' | ||
|
||
export default enhance(DataViewerPage) |
Oops, something went wrong.