Skip to content

Commit 4783fcc

Browse files
krivarddmytrotskokorlaxxalrokmelange396
authored
API keys (#1115)
lol, good luck reading this list... * very basic admin interface * list all known roles * remove log statement * fixup tests * add record flag to user * basic record based on flag logging * rename column to tracking * add webhook endpoint for google forms and simplify table * tests for simplified api_user * prepare for sending mails with mailgun * disable security check for test setup * fix tests * add registered flag * request a simple api key form with recaptcha check * implement rate limiting * registered flag not saved * mark all tests no rate limit * add link to registration form within api key form * elevate sqlalchemy log level to ERROR for test purpose * add structlog to requirements * add structured logging module * implement api key scrubbing logs and getter functions for User class * minor commenting change * change logging to kward format and add a get function for API key * move mask_apikey function out of User class * minor change in variable name * Fixed test * added missing import * Fixed _is_public_route method. Added URL_PREFIX to list of routes * Added email column to User table * Fixed tests * Added Dockerfile for Redis * Made email optional * Added email address validaiton * Fixed API key creation via /create_key endpoint * Fixed /register endpoint after google script refactoring * Fixed registration * Reverted some changes in _config.py * Reverted changes in .env.example * Code refactoring * Removed unused variables * Code cleaning * Removed unused variables * Removed default redis configuration file (it is not needed for now) * Moved BASE_URL and auth to setUP, formatted code * Moved BASE_URL and auth to setUP(), formatted code * Revert "Moved BASE_URL and auth to setUP(), formatted code" This reverts commit b63faa3. * Formatted code & removed unused imports. Defined BASE_URL inside Epidata class and removed all BASE_URL variable definition in UnitTests. Removed version for `newrelic` in requirements.txt to use the latest one. * Created staticmethod _make_rqeuest() and reused it in test_caching() method. * Returned BASE_URL and auth back, because if we use default BASE_URL from Epidata class, tests will send requests to the wrong address and fail * Completely removed patch_flask_config() function as it is useless. There is no need to patch app.config is this case, because we are using that variables directly from _config.py * Removed duplicated _logger.py file (this is exact copy of src/acquisition/covidcast/logger.py). Changed _security.py to use that logger. * Fixed test * Removed unused method * Added missing changes in Dockerfiles for copying logger * Fixed misspelled filename * Added missing variable in CSVPrinter * Formatted code * Removed tests for admin endpoint for now * Moved config variables from _security to _config. Removed duplicated method in _security.py by creating parent class for DBUser and APIUser classes. * Added missing changes * Replaced db.execute delete and update with built-it sqlalchemy functions. * Removed email field. Edited google form link to prefill tracking consent option as Yes * Removed api_user ddl * Changed user roles to use m2m table instead of string in api_user table * Added new variable for api key expiration date * Updated admin endpoint. Removed email from user details and added creation_date, expiration_date and last_api_access_date fields * Updated integration tests * Updated endpoints to register user role on endpoint load * Removed user_role FK in api_user table. Consolidated DBUser and APIUser into 1 class -> APIUser. * Updated according to new structure * Removed API_KEY_EXPIRE_AFTER variable * Removed creation_date, expiration_date and last_api_access_date from admin UI as we don't have them anymore * Added roles registraion on endpoints load * Removed role registration statement * Fixed integration tests. Actually reverted latest changes as api_user table can be truncated again * Added new ddls * Fixed wrong import * Fixed issue after resolving conflicts * Moved admin endpoint to another file into endpoints folder * Removed from _security.py all unnecessary functions * Changed roles registration process. Now we have only necessary roles. Prev we had roles for all the endpoints where role.name == endpoint.name which added redundant roles to the database. Also changed register_user_role method to use raw sql to insert the role. * Added IF NOT EXISTS to table creation statement * Added missing import * Moved admin models to the separate file. Now we have only 1 User class which containts all necessary methods to work with User model. * Added declarative_base and session objects to the _db.py file. To have all db related stuff into one file * Updated tests to use statement in order to clean api_user table after each test run. This is done because of returning relationship into User model. * Reverted formatting * Removed copying of _logger.py * Fixed auth props * Added missing requirements * Added authentication params * Removed unused imports * Added new columns to api_user table * Added placeholder to handle api key last usage update * Added Redis host variable * Uncommented @after_reqeust function to update last API key usage in Redis. * Build image from api-keys branch * Updates TODO with issue * Added Redis to ci.yaml. Added several more env variables for delphi_web_epidata container * Added Redis to the Makefile * Changed ratelimit handling * Added default admin password, changed rate limit * Updated ci.yaml * Changed wrong redis host name * Added -d to redis container run command * Removed tailing colon * Fixed get_multiples_count method * Temporary changed port * Added check container status step + check delphi_web_epidata logs. Muted integration tests for now * Removed --rm flag from delphi_web_epidata run command * Added check db logs step to ci.yaml * Added delphi_redis to clean up step * Reverted test changes * Moved docker run delphi_web_epidata below wait command. * Added name to run delphi_web_epidata step * Fixed issue with parsing allowed singals, removed unnecessary if/else block * Added Redis auth options (set default password) * adding dashboard signals module, plus requirements cleanup * updated _security.py:check_signals_allowlist() to use new DashboardSignals * debugging w/ headers * better ip address logging and accounting * Added admin folder to setup.cfg * Upgraded Flask-Limiter version * Moved Flask-Limiter code to a separate file. Made limit to be host based(global) instead of endpoint based. * Little refactoring, replaced MissingAPIKey exception by Unauthorized * Fixed limits for allowed signals * Added necessary changes * Removed redundant user variable * Update dev/local/Makefile wrt redis log file Co-authored-by: Katie Mazaitis <[email protected]> * reset dev/docker/python/Dockerfile * remove unused import in src/server/main.py * alpha-order argument keys in get_multiples_count() * Removed API Key registration form * Removed recaptcha secrets from _config.py * Added 'stop container if running' and option to redis entry * Moved Flask-Limiter belov Flask to keep everyting sorted properly * Added missing newline * Added proper Epidata.auth handling for aiohttp ClientSession * Added missing request arg for require_all() * Merged api-keys related ddls into 1 file, added constraints * Removed tracking and registered fields * Removed usage of removed fields (tracking, registered). Added logging. * Adjusted flask-limiter with comms * Fixed tests * Added templates folder * Removed _db.py and moved all needed code to the _common.py * Exempted public routes from update_key_last_time_used function * Removed redundant tracking, registered mentions. Added email field to the admin interface * Imported engine from _common.py instead of _db.py which was removed * Removed leftovers of the old code * Add auth support to delphi-epidata.R Includes support for testing the R client: * R added to python image * Integration test file that does toy queries of all unrestricted endpoints * `r-test` target to run the integration test file Seems to work regardless of whether you run r-test before or after python tests, even though a database reset is not included in the integration test. r-test is not included in CI. * Bring auth in delphi-epidata.py in line with current policy Also adds some nicer error handling when json parsing fails * Embetter json decoding error message Co-authored-by: melange396 <[email protected]> * Make user agent comply with spec; explain inactive R client endpoint tests * Removed api_analytics table * Added 'window' param handling in multiples. Removed hostname from limit string * Added TODO to remove api keys warning messages * Added issue handling when API Key is provided but doesn't exist in database * Fix * Changed limiter * made api key rollout phase determination more consistent * add comment about enable_admin() method * api_user table: UNSIGNED ids, removed description comments, renamed logger * move api_key argument logging, invalid api key check, and last key usage update from _security.py to _common.py (coalescing @app.before_request and @app.after_request events to one usage each) Co-authored-by: dmytrotsko <[email protected]> * missed import for _is_public_route * removed TESTING_MODE and fixed unused imports * refactored into _db.py to remove circular import dependencies * import for werkzeug Unauthorized exception * removed recaptcha references * moved missing import from _common to _db * distinguish config-sourced 'user roles' from db-based * logging additions, including experimental stuff * logging level change * user object debugging during the api request/response flow * fix logging case when there is no 'User' * Muted non-existing api key check * Formatting, added AUTH * Added 'old' endpoints auth logic * Added email/api key duplicate check * remove un-slashed app route * change url (route) prefix to be empty instead of a bare slash * API Keys: API Documentation (#1158) * Unmuted api_key validation * Removed AUTH, added TEMPORARY_API_KEY and REGISTRATION_FORM_LINK * Added requests_left() function to check user's remaining requests and in order to display warning message about limit exceed during Phase1/Phase2 * Removed old authentication, updated warning messages * Added limit exceed, multiple exceed, temporary key messages to the printers * Fixed fluview endpoint authentication * Fluview endpoint hotfix * Added ratelimit headers to the response * Adjusted limiter warning messages(Messages text taken from PR#1163). Changed default limit to 60/h. * Update _security.py -- checks for all 4 phases * solidified rate limit filter behavior Co-authored-by: dmytrotsko <[email protected]> * Fixed user update. Removed api_key check on phase 1 * Added handling for data_source&signal pairs * Fixed order of warnings * Fixed printer message * logging changes, including rows returned and api user db CrUD operations * Printer messages hotfix * Fixed printer warnings * Hotfix * _printer hotfix * Fix _printer * reduced usages of flask.g, improved usages of _get_current_user() / current_user * update api-keys config variables with now-announced values * took roles out of config (its in db now), simplified role checking in sensors.py * logging cleanup * force named arguments * update api-keys registration and removal links * added local redirects for gForms for registration and user deletion, plus reduced admin error message verbosity * fix typo in import statement * update api-key error messages to use local redirect to registration form * fix 'multiples' detection so it recognizes date ranges as well * fix 'multiples' detection, cant do instance checks w/ subscripted generics (as is ) * fix 'multiples' detection, check for list instead of Sequence) * Text check for rollout (#1171) * Fix temporary key and contact point msgs * Removed exceptions no longer in use * UnAuthenticatedException * MissingAPIKeyException * Synced rollout warnings to approved comms * Fixed per minute -> per hour, and added "free" where it was supposed to be * Increase longevity of rate limit warning Co-authored-by: melange396 <[email protected]> * Fixed expired session by using new session for each User operation * Fix environment variable and 429 output method * Propagate API key rollout env variable namechange to .env template * updated docs to local forwards for google forms links * adding key request form script * fix user_id logging (logged user w/ email before, which was removed completely. now logs id) * fixed scope for db_user * orm/user debugging * grrr stupid typo * more user/role debugging * Update usage text in src/server/admin/api_key_form_script.js Co-authored-by: Katie Mazaitis <[email protected]> * cleaning up... * changing sqlalchemy logging to match levels in dev --------- Co-authored-by: Dmytro Trotsko <[email protected]> Co-authored-by: Brian Clark <[email protected]> Co-authored-by: george haff <[email protected]>
1 parent 9922cd9 commit 4783fcc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1867
-403
lines changed

.dockerignore

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/delphi-epidata
2-
/.mypy_cache
2+
**/.mypy_cache
33
/.github
44
/docs
5-
__pycache__
6-
/node_modules
5+
**/__pycache__
6+
**/.pytest_cache
7+
**/node_modules

.env.example

+3-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
11
FLASK_DEBUG=True
22
SQLALCHEMY_DATABASE_URI=sqlite:///test.db
33
FLASK_SECRET=abc
4-
SECRET_TWITTER=abc
5-
SECRET_GHT=abc
6-
SECRET_FLUVIEW=abc
7-
SECRET_CDC=abc
8-
SECRET_SENSORS=abc
9-
SECRET_SENSOR_TWTR=abc
10-
SECRET_SENSOR_GFT=abc
11-
SECRET_SENSOR_GHT=abc
12-
SECRET_SENSOR_GHTJ=abc
13-
SECRET_SENSOR_CDC=abc
14-
SECRET_SENSOR_QUID=abc
15-
SECRET_SENSOR_WIKI=abc
16-
SECRET_QUIDEL=abc
17-
SECRET_NOROSTAT=abc
18-
SECRET_AFHSB=abc
4+
#API_KEY_REQUIRED_STARTING_AT=2021-07-30
5+
API_KEY_ADMIN_PASSWORD=abc
6+
API_KEY_REGISTER_WEBHOOK_TOKEN=abc

.github/workflows/ci.yaml

+13-5
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,31 @@ jobs:
5353
run: |
5454
docker build -t delphi_database_epidata -f ./repos/delphi/delphi-epidata/dev/docker/database/epidata/Dockerfile .
5555
docker build -t delphi_web_python -f repos/delphi/delphi-epidata/dev/docker/python/Dockerfile .
56+
sudo docker build -t delphi_redis -f repos/delphi/delphi-epidata/dev/docker/redis/Dockerfile .
5657
cd ./repos/delphi/delphi-epidata
5758
docker build -t delphi_web_epidata -f ./devops/Dockerfile .
5859
cd ../../../
5960
6061
# MODULE_NAME specifies the location of the `app` variable, the actual WSGI application object to run.
6162
# see https://github.com/tiangolo/meinheld-gunicorn-docker#module_name
62-
- name: Start services
63+
- name: Start database and Redis services
6364
run: |
6465
docker network create --driver bridge delphi-net
6566
docker run --rm -d -p 13306:3306 --network delphi-net --name delphi_database_epidata --cap-add=sys_nice delphi_database_epidata
66-
docker run --rm -d -p 10080:80 --env "MODULE_NAME=delphi.epidata.server.main" --env "SQLALCHEMY_DATABASE_URI=mysql+mysqldb://user:pass@delphi_database_epidata:3306/epidata" --env "FLASK_SECRET=abc" --env "FLASK_PREFIX=/epidata" --network delphi-net --name delphi_web_epidata delphi_web_epidata
67-
docker ps
67+
docker run --rm -d -p 6379:6379 --network delphi-net --env "REDIS_PASSWORD=1234" --name delphi_redis delphi_redis
68+
6869
6970
- run: |
7071
wget https://raw.githubusercontent.com/eficode/wait-for/master/wait-for
7172
chmod +x wait-for
7273
./wait-for localhost:13306 -- echo 'ready'
7374
sleep 10s
75+
76+
- name: Start delphi_web_epidata
77+
run: |
78+
docker run --rm -d -p 10080:80 --env "MODULE_NAME=delphi.epidata.server.main" --env "SQLALCHEMY_DATABASE_URI=mysql+mysqldb://user:pass@delphi_database_epidata:3306/epidata" --env "FLASK_SECRET=abc" --env "FLASK_PREFIX=/epidata" --env "REDIS_HOST=delphi_redis" --env "REDIS_PASSWORD=1234" --env "API_KEY_REGISTER_WEBHOOK_TOKEN=abc" --env "API_KEY_ADMIN_PASSWORD=test_admin_password" --network delphi-net --name delphi_web_epidata delphi_web_epidata
79+
docker ps
80+
7481
- name: Run Unit Tests
7582
run: |
7683
docker run --rm --network delphi-net --env "SQLALCHEMY_DATABASE_URI=mysql+mysqldb://user:pass@delphi_database_epidata:3306/epidata" --env "FLASK_SECRET=abc" delphi_web_python python -m pytest --import-mode importlib repos/delphi/delphi-epidata/tests
@@ -81,7 +88,7 @@ jobs:
8188
8289
- name: Clean Up
8390
run: |
84-
docker stop delphi_database_epidata delphi_web_epidata
91+
docker stop delphi_database_epidata delphi_web_epidata delphi_redis
8592
docker network remove delphi-net
8693
8794
build_js_client:
@@ -108,7 +115,8 @@ jobs:
108115
image:
109116
needs: build
110117
# only on main and dev branch
111-
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'
118+
# TODO: #1112 Remove `|| github.ref == 'refs/heads/api-keys'` after transition to production status.
119+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/api-keys'
112120

113121
runs-on: ubuntu-latest
114122
steps:

dev/docker/python/Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
FROM python:3.8-buster
22

3+
RUN apt-get update && apt-get install -y r-base && Rscript -e "install.packages(c('httr','xml2'))"
4+
35
WORKDIR /usr/src/app
46

57
COPY repos repos

dev/docker/redis/Dockerfile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM redis
2+
3+
ENV REDIS_PASSWORD=$REDIS_PASSWORD
4+
5+
CMD ["sh", "-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\""]

dev/local/Makefile

+35-1
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ CWD:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
6464
NOW:=$(shell date "+%Y-%m-%d")
6565
LOG_WEB:=delphi_web_epidata_$(NOW).log
6666
LOG_DB:=delphi_database_epidata_$(NOW).log
67+
LOG_REDIS:=delphi_redis_instance_$(NOW).log
6768
WEB_CONTAINER_ID:=$(shell docker ps -q --filter 'name=delphi_web_epidata')
6869
DATABASE_CONTAINER_ID:=$(shell docker ps -q --filter 'name=delphi_database_epidata')
70+
REDIS_CONTAINER_ID:=$(shell docker ps -q --filter 'name=delphi_redis')
6971

7072
M1=
7173
ifeq ($(shell uname -smp), Darwin arm64 arm)
@@ -98,6 +100,10 @@ web:
98100
--env "MODULE_NAME=delphi.epidata.server.main" \
99101
--env "SQLALCHEMY_DATABASE_URI=$(sqlalchemy_uri)" \
100102
--env "FLASK_SECRET=abc" --env "FLASK_PREFIX=/epidata" --env "LOG_DEBUG" \
103+
--env "REDIS_HOST=delphi_redis" \
104+
--env "REDIS_PASSWORD=1234" \
105+
--env "API_KEY_ADMIN_PASSWORD=test_admin_password" \
106+
--env "API_KEY_REGISTER_WEBHOOK_TOKEN=abc" \
101107
--network delphi-net --name delphi_web_epidata \
102108
delphi_web_epidata >$(LOG_WEB) 2>&1 &
103109

@@ -136,8 +142,25 @@ py:
136142
$(M1) \
137143
-f repos/delphi/delphi-epidata/dev/docker/python/Dockerfile .
138144

145+
.PHONY=redis
146+
redis:
147+
@# Stop container if running
148+
@if [ $(REDIS_CONTAINER_ID) ]; then\
149+
docker stop $(REDIS_CONTAINER_ID);\
150+
fi
151+
152+
@docker build -t delphi_redis \
153+
$(M1) \
154+
-f repos/delphi/delphi-epidata/dev/docker/redis/Dockerfile .
155+
156+
@docker run --rm -d -p 127.0.0.1:6379:6379 \
157+
$(M1) \
158+
--network delphi-net \
159+
--env "REDIS_PASSWORD=1234" \
160+
--name delphi_redis delphi_redis >$(LOG_REDIS) 2>&1 &
161+
139162
.PHONY=all
140-
all: db web py
163+
all: db web py redis
141164

142165
.PHONY=test
143166
test:
@@ -149,6 +172,17 @@ test:
149172
--env "FLASK_SECRET=abc" \
150173
delphi_web_python python -m pytest --import-mode importlib $(pdb) $(test) | tee test_output_$(NOW).log
151174

175+
.PHONY=r-test
176+
r-test:
177+
@docker run -i --rm --network delphi-net \
178+
$(M1) \
179+
--mount type=bind,source=$(CWD)repos/delphi/delphi-epidata,target=/usr/src/app/repos/delphi/delphi-epidata,readonly \
180+
--mount type=bind,source=$(CWD)repos/delphi/delphi-epidata/src,target=/usr/src/app/delphi/epidata,readonly \
181+
--env "SQLALCHEMY_DATABASE_URI=$(sqlalchemy_uri)" \
182+
--env "FLASK_SECRET=abc" \
183+
delphi_web_python Rscript repos/delphi/delphi-epidata/integrations/client/test_delphi_epidata.R | tee r-test_output_$(NOW).log
184+
185+
152186
.PHONY=bash
153187
bash:
154188
@docker run -it --rm --network delphi-net \

dev/local/setup.cfg

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ packages =
2828
delphi.epidata.acquisition.wiki
2929
delphi.epidata.client
3030
delphi.epidata.server
31+
delphi.epidata.server.admin
32+
delphi.epidata.server.admin.templates
3133
delphi.epidata.server.covidcast_issues_migration
3234
delphi.epidata.server.endpoints
3335
delphi.epidata.server.endpoints.covidcast_utils

docs/api/api_keys.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ change as we learn more about their impact:
1616

1717
For example, a query for three signals on one date across all counties can be
1818
submitted anonymously, but a query for three signals on a period of four weeks
19-
across all counties requires an API key.
19+
across all counties requires an API key.
2020

2121
An API key is a pseudonymous access token that grants privileged access to the
22-
Epidata API. You can request an API key by
23-
[registering with us](https://forms.gle/hkBr5SfQgxguAfEt7).
22+
Epidata API. You can request an API key by
23+
[registering with us](https://api.delphi.cmu.edu/epidata/admin/registration_form).
2424
Privileges of registration may include:
2525

2626
1. no rate limit
@@ -36,7 +36,8 @@ store the information you provide us at registration time, see our
3636

3737
## Usage
3838

39-
If you choose to [register for an API key](https://forms.gle/hkBr5SfQgxguAfEt7),
39+
If you choose to
40+
[register for an API key](https://api.delphi.cmu.edu/epidata/admin/registration_form),
4041
there are several ways to use your key to authenticate your requests:
4142

4243
### Via request parameter

docs/api/privacy_statement.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ purposes:
2929
* to identify excessive or abnormal usage patterns which may harm our system
3030

3131
The logs are only available to members of our operations team, and are expunged
32-
at or before they reach five years in age.
32+
at or before they reach five years in age.
3333

3434
If you provide us with your email address, we will only use it to contact you in
3535
the following scenarios:
@@ -47,9 +47,9 @@ security practices to help us keep your information secure. We only retrieve
4747
this mapping to resolve cases of excessive or abnormal usage. We automatically
4848
disassociate an email address from its API key when the API key has not been
4949
used for six months, or upon user request. You can request that your
50-
email address be removed from our records by filling out a
51-
[deletion request](https://forms.gle/GucFmZHTMgEFjH197).
50+
email address be removed from our records by filling out a
51+
[deletion request](https://api.delphi.cmu.edu/epidata/admin/removal_request).
5252

53-
For more information, see
53+
For more information, see
5454
[Carnegie Mellon’s privacy notice](https://www.cmu.edu/legal/privacy-notice.html).
5555
Further questions can be directed to [email protected].

docs/index.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ group](https://delphi.cmu.edu/). The Epidata API includes:
1414
quick access to COVID data are available.
1515
- [Data about other diseases](api/README.md), including influenza, dengue, and
1616
other diseases tracked by Delphi through various data streams.
17-
17+
1818
Anyone may access the Epidata API anonymously without providing any personal
1919
data. Anonymous API access is currently rate-limited and restricted to public
2020
datasets with a maximum of two of the requested parameters having multiple
2121
selections (signals, dates, versions, regions, etc).
2222

2323
To request access with no rate limit and unlimited multiple
24-
selections, you can [request a registered API key](https://forms.gle/hkBr5SfQgxguAfEt7).
24+
selections, you can [request a registered API key](https://api.delphi.cmu.edu/epidata/admin/registration_form).
2525
For policy and usage details, consult the [Epidata API keys documentation](api/api_keys.md).
2626

2727
If you regularly or frequently use our system, please consider using an API key
@@ -30,10 +30,11 @@ us understand who and how others are using our Delphi Epidata API, which may in
3030
turn inform our future research, data partnerships, and funding.
3131

3232
For more information about how we use the data you provide us through your
33-
registration and API request activity, see our
34-
[Privacy Statement](api/privacy_statement.md). At any time, you may submit a
35-
[Deletion Request](https://forms.gle/GucFmZHTMgEFjH197) to have us deactivate your key and destroy all
36-
information associating that key with your identity.
33+
registration and API request activity, see our
34+
[Privacy Statement](api/privacy_statement.md). At any time, you may submit a
35+
[Deletion Request](https://api.delphi.cmu.edu/epidata/admin/removal_request) to
36+
have us deactivate your key and destroy all information associating that key
37+
with your identity.
3738

3839
The Delphi group is extremely grateful to Pedrito Maynard-Zhang for all his
3940
help with the Epidata API [documentation](api/README.md).

integrations/acquisition/covid_hosp/facility/test_scenarios.py

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def setUp(self):
2929

3030
# use the local instance of the Epidata API
3131
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
32+
Epidata.auth = ('epidata', 'key')
3233

3334
# use the local instance of the epidata database
3435
secrets.db.host = 'delphi_database_epidata'
@@ -40,6 +41,8 @@ def setUp(self):
4041
cur.execute('truncate table covid_hosp_facility')
4142
cur.execute('truncate table covid_hosp_facility_key')
4243
cur.execute('truncate table covid_hosp_meta')
44+
cur.execute('delete from api_user')
45+
cur.execute('insert into api_user(api_key, email) values ("key", "emai")')
4346

4447
@freeze_time("2021-03-16")
4548
def test_acquire_dataset(self):

integrations/acquisition/covid_hosp/state_daily/test_scenarios.py

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def setUp(self):
3333

3434
# use the local instance of the Epidata API
3535
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
36+
Epidata.auth = ('epidata', 'key')
3637

3738
# use the local instance of the epidata database
3839
secrets.db.host = 'delphi_database_epidata'
@@ -43,6 +44,8 @@ def setUp(self):
4344
with db.new_cursor() as cur:
4445
cur.execute('truncate table covid_hosp_state_timeseries')
4546
cur.execute('truncate table covid_hosp_meta')
47+
cur.execute('delete from api_user')
48+
cur.execute('insert into api_user(api_key, email) values("key", "email")')
4649

4750
@freeze_time("2021-03-16")
4851
def test_acquire_dataset(self):

integrations/acquisition/covid_hosp/state_timeseries/test_scenarios.py

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def setUp(self):
2929

3030
# use the local instance of the Epidata API
3131
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
32+
Epidata.auth = ('epidata', 'key')
3233

3334
# use the local instance of the epidata database
3435
secrets.db.host = 'delphi_database_epidata'
@@ -39,6 +40,8 @@ def setUp(self):
3940
with db.new_cursor() as cur:
4041
cur.execute('truncate table covid_hosp_state_timeseries')
4142
cur.execute('truncate table covid_hosp_meta')
43+
cur.execute('delete from api_user')
44+
cur.execute('insert into api_user(api_key, email) values ("key", "email")')
4245

4346
@freeze_time("2021-03-17")
4447
def test_acquire_dataset(self):

integrations/acquisition/covidcast/test_covidcast_meta_caching.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,20 @@ def setUp(self):
6060

6161
# use the local instance of the Epidata API
6262
Epidata.BASE_URL = BASE_URL
63+
Epidata.auth = ('epidata', 'key')
6364

6465
def tearDown(self):
6566
"""Perform per-test teardown."""
6667
self.cur.close()
6768
self.cnx.close()
6869

70+
@staticmethod
71+
def _make_request():
72+
params = {'endpoint': 'covidcast_meta', 'cached': 'true'}
73+
response = requests.get(Epidata.BASE_URL, params=params, auth=Epidata.auth)
74+
response.raise_for_status()
75+
return response.json()
76+
6977
def test_caching(self):
7078
"""Populate, query, cache, query, and verify the cache."""
7179

@@ -147,10 +155,7 @@ def test_caching(self):
147155
self.cnx.commit()
148156

149157
# fetch the cached version (manually)
150-
params = {'endpoint': 'covidcast_meta', 'cached': 'true'}
151-
response = requests.get(BASE_URL, params=params)
152-
response.raise_for_status()
153-
epidata4 = response.json()
158+
epidata4 = self._make_request()
154159

155160
# make sure the cache was actually served
156161
self.assertEqual(epidata4, {
@@ -170,10 +175,7 @@ def test_caching(self):
170175
self.cnx.commit()
171176

172177
# fetch the cached version (manually)
173-
params = {'endpoint': 'covidcast_meta', 'cached': 'true'}
174-
response = requests.get(BASE_URL, params=params)
175-
response.raise_for_status()
176-
epidata5 = response.json()
178+
epidata5 = self._make_request()
177179

178180
# make sure the cache was returned anyhow
179181
self.assertEqual(epidata4, epidata5)

integrations/acquisition/covidcast/test_csv_uploading.py

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def setUp(self):
5757

5858
# use the local instance of the Epidata API
5959
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
60+
Epidata.auth = ('epidata', 'key')
6061

6162
def tearDown(self):
6263
"""Perform per-test teardown."""

integrations/acquisition/covidcast_nowcast/test_csv_uploading.py

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def setUp(self):
4141
database='epidata')
4242
cur = cnx.cursor()
4343
cur.execute('truncate table covidcast_nowcast')
44+
cur.execute('delete from api_user')
45+
cur.execute('insert into api_user(api_key, email) values ("key", "email")')
4446
cnx.commit()
4547
cur.close()
4648

@@ -54,6 +56,7 @@ def setUp(self):
5456

5557
# use the local instance of the Epidata API
5658
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
59+
Epidata.auth = ('epidata', 'key')
5760

5861
def tearDown(self):
5962
"""Perform per-test teardown."""

0 commit comments

Comments
 (0)