Skip to content

Commit

Permalink
Merge pull request #322 from cioos-siooc/development
Browse files Browse the repository at this point in the history
a whole bunch of stuff
  • Loading branch information
fostermh authored Apr 10, 2024
2 parents 7cccb26 + f0de135 commit 76980cd
Show file tree
Hide file tree
Showing 82 changed files with 27,860 additions and 34,714 deletions.
9 changes: 6 additions & 3 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{
"presets": [[
"@babel/preset-env", {
"useBuiltIns": "entry"
"useBuiltIns": "entry",
"loose": true
}],
"@babel/preset-react"],
"plugins": [
"@babel/plugin-proposal-class-properties",
["@babel/plugin-transform-class-properties",{"loose": true}],
"@babel/plugin-proposal-export-default-from",
"react-hot-loader/babel"
"react-hot-loader/babel",
["@babel/plugin-transform-private-methods",{"loose": true}],
["@babel/plugin-transform-private-property-in-object",{"loose": true}]
]
}
3 changes: 1 addition & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@
}
],
"react/prop-types": 0
},
"ignorePatterns": "*.test.js"
}
}
4 changes: 1 addition & 3 deletions .github/workflows/firebase-hosting-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install and Build 🔧
env:
NODE_OPTIONS: --openssl-legacy-provider
Expand All @@ -31,8 +31,6 @@ jobs:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
GMAIL_USER: ${{ secrets.GMAIL_USER }}
GMAIL_PASS: ${{ secrets.GMAIL_PASS }}
DATACITE_USER: ${{ secrets.DATACITE_USER }}
DATACITE_PASS: ${{ secrets.DATACITE_PASS }}
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_ACCESSKEYID: ${{ secrets.AWS_ACCESSKEYID }}
AWS_SECRETACCESSKEY: ${{ secrets.AWS_SECRETACCESSKEY }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/github-pages-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Node.js 16.x
uses: actions/setup-node@v2
- name: Set up Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '20.x'

- name: Install and Build 🔧
run: |
Expand Down
18 changes: 13 additions & 5 deletions .github/workflows/run-build-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,26 @@ on:
jobs:
build:
runs-on: ubuntu-latest

continue-on-error: true
strategy:
matrix:
node-version: [16.x]
node-version: [20.x]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm' # Enable automatic caching for npm
- name: Cache Node.js modules
uses: actions/cache@v4
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.OS }}-node-
${{ runner.OS }}-
- run: npm ci
- name: Create .env file
run: |
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ __pycache__
firebase-debug.log
.Rproj.user

.env
yarn.lock
.env
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,37 @@ CIOOS Metadata entry form

This will start a hot-reloading dev server. Click on the link that it outputs to open in your browser.

## Monitoring

Monitoring of production site availability is done via the [cioos-upptime](https://github.com/cioos-siooc/cwatch-upptime) and notices are posted to the CIOOS cwatch-upptime slack channel. Error collection is performed by sentry and reported in the [cioos-metadata-entry-form](https://hakai-institute.sentry.io/projects/cioos-metadata-entry-form/) project.

### Running the Firebase emulator

#### Local Install Alternative

Install firebase CLI [as described here](https://firebase.google.com/docs/emulator-suite/install_and_configure).

Run `firebase emulators:start` from the `firebase-functions/functions` directory.
Redirect function calls to this emulator by uncommenting the call to `useFunctionsEmulator` in [firebase.js](firebase.js).

## Deploy to testing site at GitHub pages
#### Docker Alternative
Using the firebase emulator in docker will preload some data into a local realtime database and emulate cloud functions and the realtime database

docker-compose up -d --build
Redirect function calls to this emulator by uncommenting the call to `useFunctionsEmulator` in [firebase.js](firebase.js).

## Deploy to production site at GitHub pages

Pushes to master automatically deploy to <https://cioos-siooc.github.io/metadata-entry-form/>

Or manually deploy any branch with

`npm run deploy`

## Deploy to dev preview sites

firebase hosted preview sites are created for all pull requests. Once a pull request is generated, check the pull request comments on github for the link to the preview site. Deployment is handled by the `firebase-hosting-pull-request.yml` github action. Preview sites are deleted during a pull request close event or after 30 days of inactivity on the pull request. Any commit to the pull request branch will reset the timer.

## Deployment and Configuration of Firebase Functions

Our Firebase Functions infrastructure utilizes both GitHub Actions for automated and manual deployments and parameterized configuration for management of environment variables and credentials.
Expand Down
28 changes: 28 additions & 0 deletions config-overrides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint no-param-reassign: ["error", { "props": false }] */
module.exports = function override(config) {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
crypto: require.resolve("crypto-browserify"),
stream: require.resolve("stream-browserify"),
assert: false, // require.resolve("assert") can be polyfilled here if needed
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
os: false, // require.resolve("os-browserify") can be polyfilled here if needed
url: require.resolve("url/"),
zlib: false, // require.resolve("browserify-zlib") can be polyfilled here if needed
querystring: require.resolve("querystring-es3"),
util: require.resolve("util/"),
path: require.resolve("path-browserify"),
});
config.resolve.fallback = fallback;
config.ignoreWarnings = [/Failed to parse source map/];
config.module.rules.push({
test: /\.(js|mjs|jsx)$/,
enforce: "pre",
loader: require.resolve("source-map-loader"),
resolve: {
fullySpecified: false,
},
});
return config;
};
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version: "3.3"

services:

# -------------------------------------
# Firebase Eumulator
# -------------------------------------

emulator:
image: cioos/firebase-emulator:latest
build: ./firebase-functions/
volumes:
- ./firebase-functions/firebase.json:/app/firebase.json:rw
- ./firebase-functions/firestore.rules:/app/firestore.rules
- ./firebase-functions/firestore.indexes.json:/app/firestore.indexes.json
- ./firebase-functions/functions:/app/functions
env_file:
- .env
environment:
FIREBASE_PROJECT: cioos-metadata-form
ports:
- 5002:5002 # Functions emulator
- 9001:9001 # Realtime Database
- 8081:8081
- 4000:4000 # UI
- 4400:4400
- 4500:4500
- 9299:9299
- 9099:9099 # Authentication emulator
- 9150:9150
18 changes: 18 additions & 0 deletions firebase-functions/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM node:lts-alpine AS app-env

# Install Python and Java and pre-cache emulator dependencies.
RUN apk add --no-cache python3 py3-pip openjdk11-jre bash && \
npm install -g firebase-tools && \
firebase setup:emulators:database && \
firebase setup:emulators:firestore && \
firebase setup:emulators:pubsub && \
firebase setup:emulators:storage && \
firebase setup:emulators:ui && \
rm -rf /var/cache/apk/*

WORKDIR /app

ADD ./entrypoint.sh /app/entrypoint.sh
RUN chmod 755 entrypoint.sh

ENTRYPOINT ["./entrypoint.sh"]
101 changes: 59 additions & 42 deletions firebase-functions/database.rules.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,65 @@
{
"rules": {
// Firebase security rules cascade, meaning that if a user is granted read or write permissions
// at a higher (parent) level, those permissions cannot be revoked at a lower (child) level.
// This design requires careful structuring of rules (and data) to ensure appropriate access control
// throughout the database hierarchy.
"$region": {
// Allow read access to any authenticated user.
".read": "auth.uid != null",
"users": {
"$userid": {
// Allow write access if the authenticated user is the user specified by $userid or if the authenticated user's email is listed as a reviewer in the admin permissions for the region.
".write": "(auth.uid == $userid) || root.child('admin').child($region).child('permissions').child('reviewers').val().contains(auth.email)"
}
"rules": {
// Firebase security rules cascade, meaning that if a user is granted read or write permissions
// at a higher (parent) level, those permissions cannot be revoked at a lower (child) level.
// This design requires careful structuring of rules (and data) to ensure appropriate access control
// throughout the database hierarchy.
"$region": {
// Allow read access to any authenticated user.
".read": "auth.uid != null",
"shares": {
"$userid": {
// Allow write access to any authenticated user.
// This rule permits user A to share a record with user B by writing to user B's 'shares' node.
".write": "auth.uid != null",
}
},
"admin": { // Section of the database dedicated to admin configurations.
"$regionAdmin": {
// Allow read access if the authenticated user's email is listed as a reviewer in the permissions for the region.
".read": "root.child('admin').child($regionAdmin).child('permissions').child('reviewers').val().contains(auth.email)",
"projects": {
// Allow write access to projects if the authenticated user's email is listed as a reviewer in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('reviewers').val().contains(auth.email)",
// Allow read access to any authenticated user.
".read": "auth.uid != null"
},
"permissions": {
// Allow read access to any authenticated user.
".read": "auth.uid != null",
"admins": {
// Allow write access for admins if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
},
"reviewers": {
// Allow write access for reviewers if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
// Allow read access to any authenticated user.
".read": "auth.uid != null",
}
},
"dataciteCredentials": {
// Allow write access to DataCite credentials if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
}
"users": {
"$userid": {
// Allow write access if the authenticated user is the user specified by $userid or if the authenticated user's email is listed as a reviewer in the admin permissions for the region.
".write": "(auth.uid == $userid) || root.child('admin').child($region).child('permissions').child('reviewers').val().contains(auth.email)",
"records": {
"$recordid": {
// Allow read access if the authenticated users's uid is listed in the 'shared with' list for the record
".read": "root.child($region).child('users').child($userid).child('records').child($recordid).child('sharedWith').child(auth.uid).exists()",
// Allow write access if the authenticated users's uid is listed in the 'shared with' list for the record
".write": "root.child($region).child('users').child($userid).child('records').child($recordid).child('sharedWith').child(auth.uid).exists()",
}
},
}
}
},
"admin": { // Section of the database dedicated to admin configurations.
"$regionAdmin": {
// Allow read access if the authenticated user's email is listed as a reviewer in the permissions for the region.
".read": "root.child('admin').child($regionAdmin).child('permissions').child('reviewers').val().contains(auth.email) || root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
"projects": {
// Allow write access to projects if the authenticated user's email is listed as a reviewer in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('reviewers').val().contains(auth.email)",
// Allow read access to any authenticated user.
".read": "auth.uid != null"
},
"permissions": {
// Allow read access to any authenticated user.
".read": "auth.uid != null",
"admins": {
// Allow write access for admins if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
// Allow read access to any authenticated user.
".read": "auth.uid != null"
},
"reviewers": {
// Allow write access for reviewers if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
// Allow read access to any authenticated user.
".read": "auth.uid != null"
}
},
"dataciteCredentials": {
// Allow write access to DataCite credentials if the authenticated user's email is listed as an admin in the permissions for the region.
".write": "root.child('admin').child($regionAdmin).child('permissions').child('admins').val().contains(auth.email)",
}
}
}
}
}
}
7 changes: 7 additions & 0 deletions firebase-functions/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

echo "Launching emulator with following firebase.json config file"
cat firebase.json

npm --prefix ./functions install
firebase emulators:start --project=cioos-metadata-form --only=firestore,database,functions,auth
17 changes: 13 additions & 4 deletions firebase-functions/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@
},
"emulators": {
"functions": {
"port": 5002
"port": 5002,
"host": "0.0.0.0"
},
"database": {
"port": 9001
"port": 9001,
"host": "0.0.0.0"
},
"ui": {
"enabled": true
"enabled": true,
"host": "0.0.0.0",
"port": "4000"
},
"firestore": {
"port": 8081
"port": 8081,
"host": "0.0.0.0"
},
"auth": {
"port": 9099,
"host": "0.0.0.0"
},
"singleProjectMode": true
},
Expand Down
2 changes: 1 addition & 1 deletion firebase-functions/functions/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 firebase-functions/functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase emulators:start --only functions",
"serve": "firebase emulators:start",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
Expand Down
Loading

0 comments on commit 76980cd

Please sign in to comment.