We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Sentry to API
## Problem
<!-- Describe a problem solved by this feature; or delete the section entirely. -->
We don't have any visibility into the API service. Sentry would be a good and easy first step.

## Description
<!-- Describe the feature and how it solves the problem. -->
Let's add Sentry. Long term we have goals of adding other monitoring but Sentry is a good and easy first step.

## Additional context
<!-- Add any other context about the feature here; or delete the section entirely. -->

## Implementation
<!-- Replace the [ ] with [x] to check the box. -->
- [x] 🙋 I would be interested in implementing this feature.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `openverse_api/catalog/settings.py`
Content:
```
1 """
2 Django settings for catalog project.
3 
4 Generated by 'django-admin startproject' using Django 2.0.5.
5 
6 For more information on this file, see
7 https://docs.djangoproject.com/en/2.0/topics/settings/
8 
9 For the full list of settings and their values, see
10 https://docs.djangoproject.com/en/2.0/ref/settings/
11 """
12 
13 from pathlib import Path
14 from socket import gethostbyname, gethostname
15 
16 from decouple import config
17 
18 
19 # Build paths inside the project like this: BASE_DIR.join('dir', 'subdir'...)
20 BASE_DIR = Path(__file__).resolve().parent.parent
21 
22 # Where to collect static files in production/development deployments
23 STATIC_ROOT = "/var/api_static_content/static"
24 
25 # Logo uploads
26 MEDIA_ROOT = "/var/api_media/"
27 MEDIA_URL = "/media/"
28 
29 # Quick-start development settings - unsuitable for production
30 # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
31 
32 # SECURITY WARNING: keep the secret key used in production secret!
33 SECRET_KEY = config("DJANGO_SECRET_KEY")  # required
34 
35 # SECURITY WARNING: don't run with debug turned on in production!
36 DEBUG = config("DJANGO_DEBUG_ENABLED", default=False, cast=bool)
37 
38 ALLOWED_HOSTS = [
39     "api-dev.openverse.engineering",
40     "api.openverse.engineering",
41     gethostname(),
42     gethostbyname(gethostname()),
43 ]
44 
45 if lb_url := config("LOAD_BALANCER_URL", default=""):
46     ALLOWED_HOSTS.append(lb_url)
47 
48 if DEBUG:
49     ALLOWED_HOSTS += [
50         "localhost",
51         "127.0.0.1",
52         "0.0.0.0",
53     ]
54 
55 # Domains that shortened links may point to
56 SHORT_URL_WHITELIST = {
57     "api-dev.openverse.engineering",
58     "api.openverse.engineering",
59     "localhost:8000",
60 }
61 SHORT_URL_PATH_WHITELIST = ["/v1/list", "/v1/images/"]
62 
63 USE_S3 = config("USE_S3", default=False, cast=bool)
64 
65 # Application definition
66 
67 INSTALLED_APPS = [
68     "catalog",
69     "catalog.api",
70     "drf_yasg",
71     "django.contrib.admin",
72     "django.contrib.auth",
73     "django.contrib.contenttypes",
74     "django.contrib.sessions",
75     "django.contrib.messages",
76     "django.contrib.staticfiles",
77     "oauth2_provider",
78     "rest_framework",
79     "corsheaders",
80     "sslserver",
81 ]
82 
83 if USE_S3:
84     DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
85     AWS_STORAGE_BUCKET_NAME = config("LOGOS_BUCKET", default="openverse_api-logos-prod")
86     AWS_S3_SIGNATURE_VERSION = "s3v4"
87     INSTALLED_APPS.append("storages")
88 
89 MIDDLEWARE = [
90     "django.middleware.security.SecurityMiddleware",
91     "django.contrib.sessions.middleware.SessionMiddleware",
92     "corsheaders.middleware.CorsMiddleware",
93     "django.middleware.common.CommonMiddleware",
94     "django.middleware.csrf.CsrfViewMiddleware",
95     "django.contrib.auth.middleware.AuthenticationMiddleware",
96     "django.contrib.messages.middleware.MessageMiddleware",
97     "django.middleware.clickjacking.XFrameOptionsMiddleware",
98     "oauth2_provider.middleware.OAuth2TokenMiddleware",
99 ]
100 
101 SWAGGER_SETTINGS = {"SECURITY_DEFINITIONS": {}}
102 
103 OAUTH2_PROVIDER = {
104     "SCOPES": {
105         "read": "Read scope",
106         "write": "Write scope",
107     }
108 }
109 
110 OAUTH2_PROVIDER_APPLICATION_MODEL = "api.ThrottledApplication"
111 
112 REST_FRAMEWORK = {
113     "DEFAULT_AUTHENTICATION_CLASSES": (
114         "oauth2_provider.contrib.rest_framework.OAuth2Authentication",
115     ),
116     "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
117     "DEFAULT_RENDERER_CLASSES": (
118         "rest_framework.renderers.JSONRenderer",
119         "rest_framework.renderers.BrowsableAPIRenderer",
120         "rest_framework_xml.renderers.XMLRenderer",
121     ),
122     "DEFAULT_THROTTLE_CLASSES": (
123         "catalog.api.utils.throttle.BurstRateThrottle",
124         "catalog.api.utils.throttle.SustainedRateThrottle",
125         "catalog.api.utils.throttle.OAuth2IdThrottleSustainedRate",
126         "catalog.api.utils.throttle.OAuth2IdThrottleBurstRate",
127         "catalog.api.utils.throttle.EnhancedOAuth2IdThrottleSustainedRate",
128         "catalog.api.utils.throttle.EnhancedOAuth2IdThrottleBurstRate",
129     ),
130     "DEFAULT_THROTTLE_RATES": {
131         "anon_burst": "60/min",
132         "anon_sustained": "5000/day",
133         "oauth2_client_credentials_sustained": "10000/day",
134         "oauth2_client_credentials_burst": "100/min",
135         "enhanced_oauth2_client_credentials_sustained": "20000/day",
136         "enhanced_oauth2_client_credentials_burst": "200/min",
137     },
138     "EXCEPTION_HANDLER": "catalog.api.utils.exceptions.exception_handler",
139 }
140 
141 if config("DISABLE_GLOBAL_THROTTLING", default=True, cast=bool):
142     del REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]
143     del REST_FRAMEWORK["DEFAULT_THROTTLE_CLASSES"]
144 
145 REDIS_HOST = config("REDIS_HOST", default="localhost")
146 REDIS_PORT = config("REDIS_PORT", default=6379, cast=int)
147 REDIS_PASSWORD = config("REDIS_PASSWORD", default="")
148 CACHES = {
149     # Site cache writes to 'default'
150     "default": {
151         "BACKEND": "django_redis.cache.RedisCache",
152         "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/0",
153         "OPTIONS": {
154             "CLIENT_CLASS": "django_redis.client.DefaultClient",
155         },
156     },
157     # For rapidly changing stats that we don't want to hammer the database with
158     "traffic_stats": {
159         "BACKEND": "django_redis.cache.RedisCache",
160         "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/1",
161         "OPTIONS": {
162             "CLIENT_CLASS": "django_redis.client.DefaultClient",
163         },
164     },
165     # For ensuring consistency among multiple Django workers and servers.
166     # Used by Redlock.
167     "locks": {
168         "BACKEND": "django_redis.cache.RedisCache",
169         "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/2",
170         "OPTIONS": {
171             "CLIENT_CLASS": "django_redis.client.DefaultClient",
172         },
173     },
174 }
175 
176 # Produce CC-hosted thumbnails dynamically through a proxy.
177 THUMBNAIL_PROXY_URL = config("THUMBNAIL_PROXY_URL", default="http://localhost:8222")
178 
179 THUMBNAIL_WIDTH_PX = 600
180 
181 AUTHENTICATION_BACKENDS = (
182     "oauth2_provider.backends.OAuth2Backend",
183     "django.contrib.auth.backends.ModelBackend",
184 )
185 
186 ROOT_URLCONF = "catalog.urls"
187 
188 TEMPLATES = [
189     {
190         "BACKEND": "django.template.backends.django.DjangoTemplates",
191         "DIRS": [BASE_DIR.joinpath("catalog", "templates")],
192         "APP_DIRS": True,
193         "OPTIONS": {
194             "context_processors": [
195                 "django.template.context_processors.debug",
196                 "django.template.context_processors.request",
197                 "django.contrib.auth.context_processors.auth",
198                 "django.contrib.messages.context_processors.messages",
199             ],
200         },
201     },
202 ]
203 
204 WSGI_APPLICATION = "catalog.wsgi.application"
205 
206 # Database
207 # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
208 
209 DATABASES = {
210     "default": {
211         "ENGINE": "django.db.backends.postgresql",
212         "HOST": config("DJANGO_DATABASE_HOST", default="localhost"),
213         "PORT": config("DJANGO_DATABASE_PORT", default=5432, cast=int),
214         "USER": config("DJANGO_DATABASE_USER", default="deploy"),
215         "PASSWORD": config("DJANGO_DATABASE_PASSWORD", default="deploy"),
216         "NAME": config("DJANGO_DATABASE_NAME", default="openledger"),
217     },
218     "upstream": {
219         "ENGINE": "django.db.backends.postgresql",
220         "HOST": config("UPSTREAM_DATABASE_HOST", default="localhost"),
221         "PORT": config("UPSTREAM_DATABASE_PORT", default=5433, cast=int),
222         "USER": config("UPSTREAM_DATABASE_USER", default="deploy"),
223         "PASSWORD": config("UPSTREAM_DATABASE_PASSWORD", default="deploy"),
224         "NAME": config("UPSTREAM_DATABASE_NAME", default="openledger"),
225     },
226 }
227 
228 # Password validation
229 # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
230 
231 AUTH_PASSWORD_VALIDATORS = [
232     {
233         "NAME": "django.contrib.auth.password_validation"
234         ".UserAttributeSimilarityValidator",
235     },
236     {
237         "NAME": "django.contrib.auth.password_validation" ".MinimumLengthValidator",
238     },
239     {
240         "NAME": "django.contrib.auth.password_validation" ".CommonPasswordValidator",
241     },
242     {
243         "NAME": "django.contrib.auth.password_validation" ".NumericPasswordValidator",
244     },
245 ]
246 
247 LOGGING = {
248     "version": 1,
249     "disable_existing_loggers": False,
250     "handlers": {
251         "console": {
252             "level": "INFO",
253             "class": "logging.StreamHandler",
254         },
255     },
256     "loggers": {
257         "django": {
258             "handlers": ["console"],
259             "level": "INFO",
260             "propagate": True,
261         },
262         # root logger
263         "": {
264             "level": "INFO",
265             "handlers": ["console"],
266         },
267     },
268 }
269 
270 # Internationalization
271 # https://docs.djangoproject.com/en/2.0/topics/i18n/
272 
273 LANGUAGE_CODE = "en-us"
274 
275 TIME_ZONE = "UTC"
276 
277 USE_I18N = True
278 
279 USE_L10N = True
280 
281 USE_TZ = True
282 
283 # Static files (CSS, JavaScript, Images)
284 # https://docs.djangoproject.com/en/2.0/howto/static-files/
285 
286 STATIC_URL = "/static/"
287 
288 # Allow anybody to access the API from any domain
289 CORS_ORIGIN_ALLOW_ALL = True
290 
291 # The version of the API. We follow the semantic version specification.
292 API_VERSION = config("SEMANTIC_VERSION", default="Version not specified")
293 
294 # The contact email of the Openverse team
295 CONTACT_EMAIL = config("CONTACT_EMAIL", default="openverse@wordpress.org")
296 
297 WATERMARK_ENABLED = config("WATERMARK_ENABLED", default=False, cast=bool)
298 
299 ELASTICSEARCH_URL = config("ELASTICSEARCH_URL", default="localhost")
300 ELASTICSEARCH_PORT = config("ELASTICSEARCH_PORT", default=9200, cast=int)
301 ELASTICSEARCH_AWS_REGION = config("ELASTICSEARCH_AWS_REGION", default="us-east-1")
302 
303 # Additional settings for dev/prod environments
304 AWS_ACCESS_KEY_ID = config("AWS_ACCESS_KEY_ID", default="")
305 AWS_SECRET_ACCESS_KEY = config("AWS_SECRET_ACCESS_KEY", default="")
306 
307 EMAIL_SENDER = config("EMAIL_SENDER", default="")
308 EMAIL_HOST = config("EMAIL_HOST", default="")
309 EMAIL_PORT = config("EMAIL_PORT", default=25, cast=int)
310 EMAIL_HOST_USER = config("EMAIL_HOST_USER", default="")
311 EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default="")
312 EMAIL_SUBJECT_PREFIX = "[noreply]"
313 EMAIL_USE_TLS = True
314 
315 if EMAIL_HOST_USER or EMAIL_HOST_PASSWORD:
316     EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
317 else:
318     EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
319 
320 # Log full Elasticsearch response
321 VERBOSE_ES_RESPONSE = config("DEBUG_SCORES", default=False, cast=bool)
322 
323 # Whether to boost results by authority and popularity
324 USE_RANK_FEATURES = config("USE_RANK_FEATURES", default=True, cast=bool)
325
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/openverse_api/catalog/settings.py b/openverse_api/catalog/settings.py
--- a/openverse_api/catalog/settings.py
+++ b/openverse_api/catalog/settings.py
@@ -13,7 +13,9 @@
 from pathlib import Path
 from socket import gethostbyname, gethostname
 
+import sentry_sdk
 from decouple import config
+from sentry_sdk.integrations.django import DjangoIntegration
 
 
 # Build paths inside the project like this: BASE_DIR.join('dir', 'subdir'...)
@@ -35,6 +37,8 @@
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = config("DJANGO_DEBUG_ENABLED", default=False, cast=bool)
 
+PYTHON_ENV = config("PYTHON_ENV", default="production")
+
 ALLOWED_HOSTS = [
     "api-dev.openverse.engineering",
     "api.openverse.engineering",
@@ -322,3 +326,18 @@
 
 # Whether to boost results by authority and popularity
 USE_RANK_FEATURES = config("USE_RANK_FEATURES", default=True, cast=bool)
+
+SENTRY_DSN = config(
+    "SENTRY_DSN",
+    default="https://08f4706d16004f57bcd37eb907bfc2e7@o787041.ingest.sentry.io/6107216",
+)
+SENTRY_SAMPLE_RATE = config("SENTRY_SAMPLE_RATE", default=1.0, cast=float)
+
+if not DEBUG:
+    sentry_sdk.init(
+        dsn=SENTRY_DSN,
+        integrations=[DjangoIntegration()],
+        traces_sample_rate=SENTRY_SAMPLE_RATE,
+        send_default_pii=False,
+        environment=PYTHON_ENV,
+    )

{"golden_diff": "diff --git a/openverse_api/catalog/settings.py b/openverse_api/catalog/settings.py\n--- a/openverse_api/catalog/settings.py\n+++ b/openverse_api/catalog/settings.py\n@@ -13,7 +13,9 @@\n from pathlib import Path\n from socket import gethostbyname, gethostname\n \n+import sentry_sdk\n from decouple import config\n+from sentry_sdk.integrations.django import DjangoIntegration\n \n \n # Build paths inside the project like this: BASE_DIR.join('dir', 'subdir'...)\n@@ -35,6 +37,8 @@\n # SECURITY WARNING: don't run with debug turned on in production!\n DEBUG = config(\"DJANGO_DEBUG_ENABLED\", default=False, cast=bool)\n \n+PYTHON_ENV = config(\"PYTHON_ENV\", default=\"production\")\n+\n ALLOWED_HOSTS = [\n     \"api-dev.openverse.engineering\",\n     \"api.openverse.engineering\",\n@@ -322,3 +326,18 @@\n \n # Whether to boost results by authority and popularity\n USE_RANK_FEATURES = config(\"USE_RANK_FEATURES\", default=True, cast=bool)\n+\n+SENTRY_DSN = config(\n+    \"SENTRY_DSN\",\n+    default=\"https://08f4706d16004f57bcd37eb907bfc2e7@o787041.ingest.sentry.io/6107216\",\n+)\n+SENTRY_SAMPLE_RATE = config(\"SENTRY_SAMPLE_RATE\", default=1.0, cast=float)\n+\n+if not DEBUG:\n+    sentry_sdk.init(\n+        dsn=SENTRY_DSN,\n+        integrations=[DjangoIntegration()],\n+        traces_sample_rate=SENTRY_SAMPLE_RATE,\n+        send_default_pii=False,\n+        environment=PYTHON_ENV,\n+    )\n", "issue": "Add Sentry to API\n## Problem\r\n<!-- Describe a problem solved by this feature; or delete the section entirely. -->\r\nWe don't have any visibility into the API service. Sentry would be a good and easy first step.\r\n\r\n## Description\r\n<!-- Describe the feature and how it solves the problem. -->\r\nLet's add Sentry. Long term we have goals of adding other monitoring but Sentry is a good and easy first step.\r\n\r\n## Additional context\r\n<!-- Add any other context about the feature here; or delete the section entirely. -->\r\n\r\n## Implementation\r\n<!-- Replace the [ ] with [x] to check the box. -->\r\n- [x] \ud83d\ude4b I would be interested in implementing this feature.\r\n\n", "before_files": [{"content": "\"\"\"\nDjango settings for catalog project.\n\nGenerated by 'django-admin startproject' using Django 2.0.5.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/2.0/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/2.0/ref/settings/\n\"\"\"\n\nfrom pathlib import Path\nfrom socket import gethostbyname, gethostname\n\nfrom decouple import config\n\n\n# Build paths inside the project like this: BASE_DIR.join('dir', 'subdir'...)\nBASE_DIR = Path(__file__).resolve().parent.parent\n\n# Where to collect static files in production/development deployments\nSTATIC_ROOT = \"/var/api_static_content/static\"\n\n# Logo uploads\nMEDIA_ROOT = \"/var/api_media/\"\nMEDIA_URL = \"/media/\"\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = config(\"DJANGO_SECRET_KEY\")  # required\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = config(\"DJANGO_DEBUG_ENABLED\", default=False, cast=bool)\n\nALLOWED_HOSTS = [\n    \"api-dev.openverse.engineering\",\n    \"api.openverse.engineering\",\n    gethostname(),\n    gethostbyname(gethostname()),\n]\n\nif lb_url := config(\"LOAD_BALANCER_URL\", default=\"\"):\n    ALLOWED_HOSTS.append(lb_url)\n\nif DEBUG:\n    ALLOWED_HOSTS += [\n        \"localhost\",\n        \"127.0.0.1\",\n        \"0.0.0.0\",\n    ]\n\n# Domains that shortened links may point to\nSHORT_URL_WHITELIST = {\n    \"api-dev.openverse.engineering\",\n    \"api.openverse.engineering\",\n    \"localhost:8000\",\n}\nSHORT_URL_PATH_WHITELIST = [\"/v1/list\", \"/v1/images/\"]\n\nUSE_S3 = config(\"USE_S3\", default=False, cast=bool)\n\n# Application definition\n\nINSTALLED_APPS = [\n    \"catalog\",\n    \"catalog.api\",\n    \"drf_yasg\",\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"oauth2_provider\",\n    \"rest_framework\",\n    \"corsheaders\",\n    \"sslserver\",\n]\n\nif USE_S3:\n    DEFAULT_FILE_STORAGE = \"storages.backends.s3boto3.S3Boto3Storage\"\n    AWS_STORAGE_BUCKET_NAME = config(\"LOGOS_BUCKET\", default=\"openverse_api-logos-prod\")\n    AWS_S3_SIGNATURE_VERSION = \"s3v4\"\n    INSTALLED_APPS.append(\"storages\")\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"corsheaders.middleware.CorsMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n    \"oauth2_provider.middleware.OAuth2TokenMiddleware\",\n]\n\nSWAGGER_SETTINGS = {\"SECURITY_DEFINITIONS\": {}}\n\nOAUTH2_PROVIDER = {\n    \"SCOPES\": {\n        \"read\": \"Read scope\",\n        \"write\": \"Write scope\",\n    }\n}\n\nOAUTH2_PROVIDER_APPLICATION_MODEL = \"api.ThrottledApplication\"\n\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"oauth2_provider.contrib.rest_framework.OAuth2Authentication\",\n    ),\n    \"DEFAULT_VERSIONING_CLASS\": \"rest_framework.versioning.URLPathVersioning\",\n    \"DEFAULT_RENDERER_CLASSES\": (\n        \"rest_framework.renderers.JSONRenderer\",\n        \"rest_framework.renderers.BrowsableAPIRenderer\",\n        \"rest_framework_xml.renderers.XMLRenderer\",\n    ),\n    \"DEFAULT_THROTTLE_CLASSES\": (\n        \"catalog.api.utils.throttle.BurstRateThrottle\",\n        \"catalog.api.utils.throttle.SustainedRateThrottle\",\n        \"catalog.api.utils.throttle.OAuth2IdThrottleSustainedRate\",\n        \"catalog.api.utils.throttle.OAuth2IdThrottleBurstRate\",\n        \"catalog.api.utils.throttle.EnhancedOAuth2IdThrottleSustainedRate\",\n        \"catalog.api.utils.throttle.EnhancedOAuth2IdThrottleBurstRate\",\n    ),\n    \"DEFAULT_THROTTLE_RATES\": {\n        \"anon_burst\": \"60/min\",\n        \"anon_sustained\": \"5000/day\",\n        \"oauth2_client_credentials_sustained\": \"10000/day\",\n        \"oauth2_client_credentials_burst\": \"100/min\",\n        \"enhanced_oauth2_client_credentials_sustained\": \"20000/day\",\n        \"enhanced_oauth2_client_credentials_burst\": \"200/min\",\n    },\n    \"EXCEPTION_HANDLER\": \"catalog.api.utils.exceptions.exception_handler\",\n}\n\nif config(\"DISABLE_GLOBAL_THROTTLING\", default=True, cast=bool):\n    del REST_FRAMEWORK[\"DEFAULT_THROTTLE_RATES\"]\n    del REST_FRAMEWORK[\"DEFAULT_THROTTLE_CLASSES\"]\n\nREDIS_HOST = config(\"REDIS_HOST\", default=\"localhost\")\nREDIS_PORT = config(\"REDIS_PORT\", default=6379, cast=int)\nREDIS_PASSWORD = config(\"REDIS_PASSWORD\", default=\"\")\nCACHES = {\n    # Site cache writes to 'default'\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/0\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n    # For rapidly changing stats that we don't want to hammer the database with\n    \"traffic_stats\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n    # For ensuring consistency among multiple Django workers and servers.\n    # Used by Redlock.\n    \"locks\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/2\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n}\n\n# Produce CC-hosted thumbnails dynamically through a proxy.\nTHUMBNAIL_PROXY_URL = config(\"THUMBNAIL_PROXY_URL\", default=\"http://localhost:8222\")\n\nTHUMBNAIL_WIDTH_PX = 600\n\nAUTHENTICATION_BACKENDS = (\n    \"oauth2_provider.backends.OAuth2Backend\",\n    \"django.contrib.auth.backends.ModelBackend\",\n)\n\nROOT_URLCONF = \"catalog.urls\"\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"DIRS\": [BASE_DIR.joinpath(\"catalog\", \"templates\")],\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"django.template.context_processors.debug\",\n                \"django.template.context_processors.request\",\n                \"django.contrib.auth.context_processors.auth\",\n                \"django.contrib.messages.context_processors.messages\",\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = \"catalog.wsgi.application\"\n\n# Database\n# https://docs.djangoproject.com/en/2.0/ref/settings/#databases\n\nDATABASES = {\n    \"default\": {\n        \"ENGINE\": \"django.db.backends.postgresql\",\n        \"HOST\": config(\"DJANGO_DATABASE_HOST\", default=\"localhost\"),\n        \"PORT\": config(\"DJANGO_DATABASE_PORT\", default=5432, cast=int),\n        \"USER\": config(\"DJANGO_DATABASE_USER\", default=\"deploy\"),\n        \"PASSWORD\": config(\"DJANGO_DATABASE_PASSWORD\", default=\"deploy\"),\n        \"NAME\": config(\"DJANGO_DATABASE_NAME\", default=\"openledger\"),\n    },\n    \"upstream\": {\n        \"ENGINE\": \"django.db.backends.postgresql\",\n        \"HOST\": config(\"UPSTREAM_DATABASE_HOST\", default=\"localhost\"),\n        \"PORT\": config(\"UPSTREAM_DATABASE_PORT\", default=5433, cast=int),\n        \"USER\": config(\"UPSTREAM_DATABASE_USER\", default=\"deploy\"),\n        \"PASSWORD\": config(\"UPSTREAM_DATABASE_PASSWORD\", default=\"deploy\"),\n        \"NAME\": config(\"UPSTREAM_DATABASE_NAME\", default=\"openledger\"),\n    },\n}\n\n# Password validation\n# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\"\n        \".UserAttributeSimilarityValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".MinimumLengthValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".CommonPasswordValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".NumericPasswordValidator\",\n    },\n]\n\nLOGGING = {\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n    \"handlers\": {\n        \"console\": {\n            \"level\": \"INFO\",\n            \"class\": \"logging.StreamHandler\",\n        },\n    },\n    \"loggers\": {\n        \"django\": {\n            \"handlers\": [\"console\"],\n            \"level\": \"INFO\",\n            \"propagate\": True,\n        },\n        # root logger\n        \"\": {\n            \"level\": \"INFO\",\n            \"handlers\": [\"console\"],\n        },\n    },\n}\n\n# Internationalization\n# https://docs.djangoproject.com/en/2.0/topics/i18n/\n\nLANGUAGE_CODE = \"en-us\"\n\nTIME_ZONE = \"UTC\"\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/2.0/howto/static-files/\n\nSTATIC_URL = \"/static/\"\n\n# Allow anybody to access the API from any domain\nCORS_ORIGIN_ALLOW_ALL = True\n\n# The version of the API. We follow the semantic version specification.\nAPI_VERSION = config(\"SEMANTIC_VERSION\", default=\"Version not specified\")\n\n# The contact email of the Openverse team\nCONTACT_EMAIL = config(\"CONTACT_EMAIL\", default=\"openverse@wordpress.org\")\n\nWATERMARK_ENABLED = config(\"WATERMARK_ENABLED\", default=False, cast=bool)\n\nELASTICSEARCH_URL = config(\"ELASTICSEARCH_URL\", default=\"localhost\")\nELASTICSEARCH_PORT = config(\"ELASTICSEARCH_PORT\", default=9200, cast=int)\nELASTICSEARCH_AWS_REGION = config(\"ELASTICSEARCH_AWS_REGION\", default=\"us-east-1\")\n\n# Additional settings for dev/prod environments\nAWS_ACCESS_KEY_ID = config(\"AWS_ACCESS_KEY_ID\", default=\"\")\nAWS_SECRET_ACCESS_KEY = config(\"AWS_SECRET_ACCESS_KEY\", default=\"\")\n\nEMAIL_SENDER = config(\"EMAIL_SENDER\", default=\"\")\nEMAIL_HOST = config(\"EMAIL_HOST\", default=\"\")\nEMAIL_PORT = config(\"EMAIL_PORT\", default=25, cast=int)\nEMAIL_HOST_USER = config(\"EMAIL_HOST_USER\", default=\"\")\nEMAIL_HOST_PASSWORD = config(\"EMAIL_HOST_PASSWORD\", default=\"\")\nEMAIL_SUBJECT_PREFIX = \"[noreply]\"\nEMAIL_USE_TLS = True\n\nif EMAIL_HOST_USER or EMAIL_HOST_PASSWORD:\n    EMAIL_BACKEND = \"django.core.mail.backends.smtp.EmailBackend\"\nelse:\n    EMAIL_BACKEND = \"django.core.mail.backends.console.EmailBackend\"\n\n# Log full Elasticsearch response\nVERBOSE_ES_RESPONSE = config(\"DEBUG_SCORES\", default=False, cast=bool)\n\n# Whether to boost results by authority and popularity\nUSE_RANK_FEATURES = config(\"USE_RANK_FEATURES\", default=True, cast=bool)\n", "path": "openverse_api/catalog/settings.py"}], "after_files": [{"content": "\"\"\"\nDjango settings for catalog project.\n\nGenerated by 'django-admin startproject' using Django 2.0.5.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/2.0/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/2.0/ref/settings/\n\"\"\"\n\nfrom pathlib import Path\nfrom socket import gethostbyname, gethostname\n\nimport sentry_sdk\nfrom decouple import config\nfrom sentry_sdk.integrations.django import DjangoIntegration\n\n\n# Build paths inside the project like this: BASE_DIR.join('dir', 'subdir'...)\nBASE_DIR = Path(__file__).resolve().parent.parent\n\n# Where to collect static files in production/development deployments\nSTATIC_ROOT = \"/var/api_static_content/static\"\n\n# Logo uploads\nMEDIA_ROOT = \"/var/api_media/\"\nMEDIA_URL = \"/media/\"\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = config(\"DJANGO_SECRET_KEY\")  # required\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = config(\"DJANGO_DEBUG_ENABLED\", default=False, cast=bool)\n\nPYTHON_ENV = config(\"PYTHON_ENV\", default=\"production\")\n\nALLOWED_HOSTS = [\n    \"api-dev.openverse.engineering\",\n    \"api.openverse.engineering\",\n    gethostname(),\n    gethostbyname(gethostname()),\n]\n\nif lb_url := config(\"LOAD_BALANCER_URL\", default=\"\"):\n    ALLOWED_HOSTS.append(lb_url)\n\nif DEBUG:\n    ALLOWED_HOSTS += [\n        \"localhost\",\n        \"127.0.0.1\",\n        \"0.0.0.0\",\n    ]\n\n# Domains that shortened links may point to\nSHORT_URL_WHITELIST = {\n    \"api-dev.openverse.engineering\",\n    \"api.openverse.engineering\",\n    \"localhost:8000\",\n}\nSHORT_URL_PATH_WHITELIST = [\"/v1/list\", \"/v1/images/\"]\n\nUSE_S3 = config(\"USE_S3\", default=False, cast=bool)\n\n# Application definition\n\nINSTALLED_APPS = [\n    \"catalog\",\n    \"catalog.api\",\n    \"drf_yasg\",\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"oauth2_provider\",\n    \"rest_framework\",\n    \"corsheaders\",\n    \"sslserver\",\n]\n\nif USE_S3:\n    DEFAULT_FILE_STORAGE = \"storages.backends.s3boto3.S3Boto3Storage\"\n    AWS_STORAGE_BUCKET_NAME = config(\"LOGOS_BUCKET\", default=\"openverse_api-logos-prod\")\n    AWS_S3_SIGNATURE_VERSION = \"s3v4\"\n    INSTALLED_APPS.append(\"storages\")\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"corsheaders.middleware.CorsMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n    \"oauth2_provider.middleware.OAuth2TokenMiddleware\",\n]\n\nSWAGGER_SETTINGS = {\"SECURITY_DEFINITIONS\": {}}\n\nOAUTH2_PROVIDER = {\n    \"SCOPES\": {\n        \"read\": \"Read scope\",\n        \"write\": \"Write scope\",\n    }\n}\n\nOAUTH2_PROVIDER_APPLICATION_MODEL = \"api.ThrottledApplication\"\n\nREST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": (\n        \"oauth2_provider.contrib.rest_framework.OAuth2Authentication\",\n    ),\n    \"DEFAULT_VERSIONING_CLASS\": \"rest_framework.versioning.URLPathVersioning\",\n    \"DEFAULT_RENDERER_CLASSES\": (\n        \"rest_framework.renderers.JSONRenderer\",\n        \"rest_framework.renderers.BrowsableAPIRenderer\",\n        \"rest_framework_xml.renderers.XMLRenderer\",\n    ),\n    \"DEFAULT_THROTTLE_CLASSES\": (\n        \"catalog.api.utils.throttle.BurstRateThrottle\",\n        \"catalog.api.utils.throttle.SustainedRateThrottle\",\n        \"catalog.api.utils.throttle.OAuth2IdThrottleSustainedRate\",\n        \"catalog.api.utils.throttle.OAuth2IdThrottleBurstRate\",\n        \"catalog.api.utils.throttle.EnhancedOAuth2IdThrottleSustainedRate\",\n        \"catalog.api.utils.throttle.EnhancedOAuth2IdThrottleBurstRate\",\n    ),\n    \"DEFAULT_THROTTLE_RATES\": {\n        \"anon_burst\": \"60/min\",\n        \"anon_sustained\": \"5000/day\",\n        \"oauth2_client_credentials_sustained\": \"10000/day\",\n        \"oauth2_client_credentials_burst\": \"100/min\",\n        \"enhanced_oauth2_client_credentials_sustained\": \"20000/day\",\n        \"enhanced_oauth2_client_credentials_burst\": \"200/min\",\n    },\n    \"EXCEPTION_HANDLER\": \"catalog.api.utils.exceptions.exception_handler\",\n}\n\nif config(\"DISABLE_GLOBAL_THROTTLING\", default=True, cast=bool):\n    del REST_FRAMEWORK[\"DEFAULT_THROTTLE_RATES\"]\n    del REST_FRAMEWORK[\"DEFAULT_THROTTLE_CLASSES\"]\n\nREDIS_HOST = config(\"REDIS_HOST\", default=\"localhost\")\nREDIS_PORT = config(\"REDIS_PORT\", default=6379, cast=int)\nREDIS_PASSWORD = config(\"REDIS_PASSWORD\", default=\"\")\nCACHES = {\n    # Site cache writes to 'default'\n    \"default\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/0\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n    # For rapidly changing stats that we don't want to hammer the database with\n    \"traffic_stats\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/1\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n    # For ensuring consistency among multiple Django workers and servers.\n    # Used by Redlock.\n    \"locks\": {\n        \"BACKEND\": \"django_redis.cache.RedisCache\",\n        \"LOCATION\": f\"redis://{REDIS_HOST}:{REDIS_PORT}/2\",\n        \"OPTIONS\": {\n            \"CLIENT_CLASS\": \"django_redis.client.DefaultClient\",\n        },\n    },\n}\n\n# Produce CC-hosted thumbnails dynamically through a proxy.\nTHUMBNAIL_PROXY_URL = config(\"THUMBNAIL_PROXY_URL\", default=\"http://localhost:8222\")\n\nTHUMBNAIL_WIDTH_PX = 600\n\nAUTHENTICATION_BACKENDS = (\n    \"oauth2_provider.backends.OAuth2Backend\",\n    \"django.contrib.auth.backends.ModelBackend\",\n)\n\nROOT_URLCONF = \"catalog.urls\"\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"DIRS\": [BASE_DIR.joinpath(\"catalog\", \"templates\")],\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"django.template.context_processors.debug\",\n                \"django.template.context_processors.request\",\n                \"django.contrib.auth.context_processors.auth\",\n                \"django.contrib.messages.context_processors.messages\",\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = \"catalog.wsgi.application\"\n\n# Database\n# https://docs.djangoproject.com/en/2.0/ref/settings/#databases\n\nDATABASES = {\n    \"default\": {\n        \"ENGINE\": \"django.db.backends.postgresql\",\n        \"HOST\": config(\"DJANGO_DATABASE_HOST\", default=\"localhost\"),\n        \"PORT\": config(\"DJANGO_DATABASE_PORT\", default=5432, cast=int),\n        \"USER\": config(\"DJANGO_DATABASE_USER\", default=\"deploy\"),\n        \"PASSWORD\": config(\"DJANGO_DATABASE_PASSWORD\", default=\"deploy\"),\n        \"NAME\": config(\"DJANGO_DATABASE_NAME\", default=\"openledger\"),\n    },\n    \"upstream\": {\n        \"ENGINE\": \"django.db.backends.postgresql\",\n        \"HOST\": config(\"UPSTREAM_DATABASE_HOST\", default=\"localhost\"),\n        \"PORT\": config(\"UPSTREAM_DATABASE_PORT\", default=5433, cast=int),\n        \"USER\": config(\"UPSTREAM_DATABASE_USER\", default=\"deploy\"),\n        \"PASSWORD\": config(\"UPSTREAM_DATABASE_PASSWORD\", default=\"deploy\"),\n        \"NAME\": config(\"UPSTREAM_DATABASE_NAME\", default=\"openledger\"),\n    },\n}\n\n# Password validation\n# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\"\n        \".UserAttributeSimilarityValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".MinimumLengthValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".CommonPasswordValidator\",\n    },\n    {\n        \"NAME\": \"django.contrib.auth.password_validation\" \".NumericPasswordValidator\",\n    },\n]\n\nLOGGING = {\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n    \"handlers\": {\n        \"console\": {\n            \"level\": \"INFO\",\n            \"class\": \"logging.StreamHandler\",\n        },\n    },\n    \"loggers\": {\n        \"django\": {\n            \"handlers\": [\"console\"],\n            \"level\": \"INFO\",\n            \"propagate\": True,\n        },\n        # root logger\n        \"\": {\n            \"level\": \"INFO\",\n            \"handlers\": [\"console\"],\n        },\n    },\n}\n\n# Internationalization\n# https://docs.djangoproject.com/en/2.0/topics/i18n/\n\nLANGUAGE_CODE = \"en-us\"\n\nTIME_ZONE = \"UTC\"\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/2.0/howto/static-files/\n\nSTATIC_URL = \"/static/\"\n\n# Allow anybody to access the API from any domain\nCORS_ORIGIN_ALLOW_ALL = True\n\n# The version of the API. We follow the semantic version specification.\nAPI_VERSION = config(\"SEMANTIC_VERSION\", default=\"Version not specified\")\n\n# The contact email of the Openverse team\nCONTACT_EMAIL = config(\"CONTACT_EMAIL\", default=\"openverse@wordpress.org\")\n\nWATERMARK_ENABLED = config(\"WATERMARK_ENABLED\", default=False, cast=bool)\n\nELASTICSEARCH_URL = config(\"ELASTICSEARCH_URL\", default=\"localhost\")\nELASTICSEARCH_PORT = config(\"ELASTICSEARCH_PORT\", default=9200, cast=int)\nELASTICSEARCH_AWS_REGION = config(\"ELASTICSEARCH_AWS_REGION\", default=\"us-east-1\")\n\n# Additional settings for dev/prod environments\nAWS_ACCESS_KEY_ID = config(\"AWS_ACCESS_KEY_ID\", default=\"\")\nAWS_SECRET_ACCESS_KEY = config(\"AWS_SECRET_ACCESS_KEY\", default=\"\")\n\nEMAIL_SENDER = config(\"EMAIL_SENDER\", default=\"\")\nEMAIL_HOST = config(\"EMAIL_HOST\", default=\"\")\nEMAIL_PORT = config(\"EMAIL_PORT\", default=25, cast=int)\nEMAIL_HOST_USER = config(\"EMAIL_HOST_USER\", default=\"\")\nEMAIL_HOST_PASSWORD = config(\"EMAIL_HOST_PASSWORD\", default=\"\")\nEMAIL_SUBJECT_PREFIX = \"[noreply]\"\nEMAIL_USE_TLS = True\n\nif EMAIL_HOST_USER or EMAIL_HOST_PASSWORD:\n    EMAIL_BACKEND = \"django.core.mail.backends.smtp.EmailBackend\"\nelse:\n    EMAIL_BACKEND = \"django.core.mail.backends.console.EmailBackend\"\n\n# Log full Elasticsearch response\nVERBOSE_ES_RESPONSE = config(\"DEBUG_SCORES\", default=False, cast=bool)\n\n# Whether to boost results by authority and popularity\nUSE_RANK_FEATURES = config(\"USE_RANK_FEATURES\", default=True, cast=bool)\n\nSENTRY_DSN = config(\n    \"SENTRY_DSN\",\n    default=\"https://08f4706d16004f57bcd37eb907bfc2e7@o787041.ingest.sentry.io/6107216\",\n)\nSENTRY_SAMPLE_RATE = config(\"SENTRY_SAMPLE_RATE\", default=1.0, cast=float)\n\nif not DEBUG:\n    sentry_sdk.init(\n        dsn=SENTRY_DSN,\n        integrations=[DjangoIntegration()],\n        traces_sample_rate=SENTRY_SAMPLE_RATE,\n        send_default_pii=False,\n        environment=PYTHON_ENV,\n    )\n", "path": "openverse_api/catalog/settings.py"}]}