This repo hosts the code for findthemasks.com which also provides an embeddable map to other projects
Join the slack! https://join.slack.com/t/findthemasks/shared_invite/zt-ejpx15bn-6H7K51xGCWp7FEXMn1nQqw
- new dev? please look at issues and comment on something to grab it!
- Check out the Getting Started doc
- new data moderator? Join the slack and come to #data!
- not either? Say hello on Slack and check out open roles for our team here: https://findthemasks.com/volunteer
- The website reads from a Google sheet, generates a json blob, which is rendered by a Node server.
- Our curated data file updates every five minutes and can be read from https://findthemasks.com/data-us.json [US]. Each country that we serve has its own country code, i.e. data-ca.json for Canada, data-fr.json for France, etc.
- Similarly, we also offer CSV output at http://findthemasks.com/data-us.csv , with similar country-code modifications for each country.
- If reading in data and producing web output sounds like a lot to do, please read on:
We'd love for anyone to embed our map to help fight the battle against coronavirus. Please go here for detailed instructions: https://github.com/findthemasks/findthemasks/wiki/Embedding-%23findthemasks-donation-sites-page
We use virtual paths via routing rules on the server to view country-specific datasets.
For example, /us/give.html
will filter the map to the United States and /fr/give.html
will filter to France.
To view translated version of a country you can pass in a locale parameter. /us/give.html?locale=fr-FR
will show the map of the United States in French and /fr/give.html?locale=en-US
will show the map of France in English.
To add a new country, you need to set a few variables.
- Get the country code from https://www.iban.com/country-codes.
- Add the country code and a link to the donation form to
viewHelpers/getDonationFormUrl.js
. The form should include translations for all official languages in that country. - Add the translated strings for all official languages in that country in
i18n.js
. As a starting point, it is OK to launch a new language using an international variant. e.g. you can launch Canada withen
translations andfr
translations, they do not need to be localized toen-CA
andfr-CA
. - Update the list of languages and countries in
countries.js
andlocales.js
and ensure that they propagate correctly to the language and country dropdowns. Incountries.js
you should also add the name of the string for that country's administrative region. e.g. US = "State", CA "Province", FR = "Department", copy for who they should direct large donations to, and copy for who they should contact if there are no donation sites near them.
Currently information about PPE needs is contributed by members of the public through a Google Form. We have at least one form per country; for CA and CH we have one per language. See the International Forms and Data section of the Wiki for details.
Currently the data about PPE needs is stored in Google Sheets spreadsheets (one per country). Data from the forms (described above) automatically feeds into these sheets. See International Forms and Data section of the Wiki for details.
Moderation is done by volunteers in accordance with the guidance laid out in the findthemasks wiki.
/public
- The client-side code for the website./functions
- The cloud function used to generate data.json. Not needed for frontend work.
Firebase is used to pull data from our moderated datastore and then generate a data.json. There is a production environment findthemasks and a dev environment findthemasks-dev.
The setup uses cloud functions to provide http endpoints, cloud-storage to keep the generated results, and the firebase realtime database (NOT firestore) to cache oauth tokens.
Adding an oauth token requires hitting the /authgoogleapi?sheetid=longstring
on the
cloud-function endpoint and granting an OAuth token for a user that has access to the sheet.
- Install the firebase cli for your platform.
- Do once
firebase login
firebase use --add findthemasks-dev
firebase use --add findthemasks
cd functions; npm install
# Note you need node v8 or higher. Look a nvm
- Switch deployment envrionments
firebase use [findthemasks or findthemasks-dev]
- Deploy the cloud function.
cd functions; npm run deploy
Secrets and configs not checked into github are specified via cloud function configs.
To set a config:
firebase functions:config:set findthemasks.geocode_key="some_client_id"
In code, this can be retrieved via:
functions.config().findthemasks.geocode_key
In get all configs:
firebase functions:config:get
The namespace can be anything. Add new configs to the findthemasks
namespace.
Firebase comes with a local emulation environment that lets you live develop against localhost. Since we are using firebase configs, first we have to snag the configs from the environment. Do that with:
firebase functions:config:get > .runtimeconfig.json
Next generate a new Firebase Admin SDK private key here: https://console.firebase.google.com/project/findthemasks-dev/settings/serviceaccounts/adminsdk
And save it to service_key.json
Then start up the emulator. Note this will talk to the production firebase database (likely okay as the firebase database is just storing oauth tokens).
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_key.json
firebase emulators:start --only functions
This will create localhost versions of everything. Cloud functions should be on
http://localhost:5001 and console.log()
messages will
stream to the terminal.
There is also a "shell"
firebase functions:shell
that can be used, but running the emulator and hitting with a web browser is often easier in our simple case.
There are currently 2 scripts that automatically update the spreadsheet, and one that backs it up:
- fillInGeocodes: fills in the lat/lng column based on the address in the "address" column. (Note that the "address" column is defined as the column that has "address" in row 2.) Uses Google Maps geocoding API. Currently runs once/minute.
- createStandardAddress: fills in the "address" column based on the data in the "orig_address", "city", and "state" columns. Uses Google Maps geocoding API. Currently runs once/minute.
- backupSheet: makes a timestamped copy of the sheet. Currently runs once every 2 hours.
There are a few important things to know about these scripts:
- They are visible by navigating to tools > script editor from the Google Sheet.
- They can be run by anyone who has edit permission to the Google Sheet.
- Triggers (automation) can be set up by navigating to Edit > Edit current project's triggers.
- The dev-owner of each sheet should set up a trigger for each of the 3 scripts. (US spreadsheet dev owner is @susanashlock's gmail).
- The scripts are run using quota of the user the user that runs them.
- Each Gmail user has a fixed amount of geocoding quota per day. This quota is somewhere around 250 calls per day. @susanashlock's account has 'special' quota. We're not sure exactly what it is, but is sufficient to support about 1000 calls per day.
To work on the frontend, you'll need to run a development server.
On mac, brew install npm
npm install
You'll need to do this once when first setting up, and periodically as dependencies change. The dev server script (see next section) will crap out with an error message when a new dependency is added - this is your cue to run 'npm install' again.
npm run dev
This should start a server running on http://localhost:3000
- The "Face With Medical Mask" favicon is used with thanks to favicon.io which provides pre-generated favicon packages using Twemoji. Twemoji graphics are licensed CC-BY 4.0.
- Feather icon collection, licensed under MIT License.
- HatScripts circle flags collection, licensed under MIT License.