We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Remove unused API docs cruft
Since we're moving to the RPC endpoint style, we need to remove the remaining pieces of the REST API documentation infrastructure.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `config/settings/common_settings.py`
Content:
```
1 """
2 Base settings to build other settings files upon.
3 
4 Generated by 'django-admin startproject' using Django 3.1.7.
5 
6 For more information on this file, see
7 https://docs.djangoproject.com/en/3.1/topics/settings/
8 
9 For the full list of settings and their values, see
10 https://docs.djangoproject.com/en/3.1/ref/settings/
11 """
12 
13 import os
14 from pathlib import Path
15 
16 from decouple import Csv, config as decouple_config
17 from dj_database_url import parse as db_url
18 
19 
20 # We use a 'tuple' with pipes as delimiters as decople naively splits the global
21 # variables on commas when casting to Csv()
22 def pipe_delim(pipe_string):
23     # Remove opening and closing brackets
24     pipe_string = pipe_string[1:-1]
25     # Split on pipe delim
26     return pipe_string.split("|")
27 
28 
29 # Build paths inside the project like this: BASE_DIR / 'subdir'.
30 BASE_DIR = Path(__file__).resolve().parent.parent.parent
31 
32 # Application definition
33 
34 INSTALLED_APPS = [
35     "django.contrib.admin",
36     "django.contrib.auth",
37     "django.contrib.contenttypes",
38     "django.contrib.sessions",
39     "django.contrib.messages",
40     "whitenoise.runserver_nostatic",
41     "django.contrib.staticfiles",
42     "rest_framework",
43     "django_filters",
44     "django_property_filter",
45     "drf_spectacular",
46     "modernrpc",
47     "mathesar",
48 ]
49 
50 MIDDLEWARE = [
51     "django.middleware.security.SecurityMiddleware",
52     "whitenoise.middleware.WhiteNoiseMiddleware",
53     "django.contrib.sessions.middleware.SessionMiddleware",
54     "django.middleware.locale.LocaleMiddleware",
55     "django.middleware.common.CommonMiddleware",
56     "django.middleware.csrf.CsrfViewMiddleware",
57     "django.contrib.auth.middleware.AuthenticationMiddleware",
58     "django.contrib.messages.middleware.MessageMiddleware",
59     "django.middleware.clickjacking.XFrameOptionsMiddleware",
60     "mathesar.middleware.CursorClosedHandlerMiddleware",
61     "mathesar.middleware.PasswordChangeNeededMiddleware",
62     'django_userforeignkey.middleware.UserForeignKeyMiddleware',
63     'django_request_cache.middleware.RequestCacheMiddleware',
64 ]
65 
66 ROOT_URLCONF = "config.urls"
67 
68 MODERNRPC_METHODS_MODULES = [
69     'mathesar.rpc.connections'
70 ]
71 
72 TEMPLATES = [
73     {
74         "BACKEND": "django.template.backends.django.DjangoTemplates",
75         "DIRS": [],
76         "APP_DIRS": True,
77         "OPTIONS": {
78             "context_processors": [
79                 "config.context_processors.frontend_settings",
80                 "django.template.context_processors.debug",
81                 "django.template.context_processors.request",
82                 "django.contrib.auth.context_processors.auth",
83                 "django.contrib.messages.context_processors.messages",
84                 "mathesar.template_context_processors.base_template_extensions.script_extension_templates"
85             ],
86         },
87     },
88 ]
89 
90 WSGI_APPLICATION = "config.wsgi.application"
91 
92 # Database
93 # https://docs.djangoproject.com/en/3.1/ref/settings/#databases
94 
95 # TODO: Add to documentation that database keys should not be than 128 characters.
96 
97 # MATHESAR_DATABASES should be of the form '({db_name}|{db_url}), ({db_name}|{db_url})'
98 # See pipe_delim above for why we use pipes as delimiters
99 DATABASES = {
100     db_key: db_url(url_string)
101     for db_key, url_string in decouple_config('MATHESAR_DATABASES', default='', cast=Csv(pipe_delim))
102 }
103 
104 # POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST & POSTGRES_PORT are required env variables for forming a pg connection string for the django database
105 # lack of any one of these will result in the internal django database to be sqlite.
106 POSTGRES_DB = decouple_config('POSTGRES_DB', default=None)
107 POSTGRES_USER = decouple_config('POSTGRES_USER', default=None)
108 POSTGRES_PASSWORD = decouple_config('POSTGRES_PASSWORD', default=None)
109 POSTGRES_HOST = decouple_config('POSTGRES_HOST', default=None)
110 POSTGRES_PORT = decouple_config('POSTGRES_PORT', default=None)
111 
112 if POSTGRES_DB and POSTGRES_USER and POSTGRES_PASSWORD and POSTGRES_HOST and POSTGRES_PORT:
113     DATABASES['default'] = db_url(f'postgres://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}')
114 else:
115     DATABASES['default'] = db_url('sqlite:///db.sqlite3')
116 
117 for db_key, db_dict in DATABASES.items():
118     # Engine should be '.postgresql' or '.postgresql_psycopg2' for all db(s),
119     # however for the internal 'default' db 'sqlite3' can be used.
120     if not db_dict['ENGINE'].startswith('django.db.backends.postgresql') and db_key != 'default':
121         raise ValueError(
122             f"{db_key} is not a PostgreSQL database. "
123             f"{db_dict['ENGINE']} found for {db_key}'s engine."
124         )
125 
126 # pytest-django will create a new database named 'test_{DATABASES[table_db]['NAME']}'
127 # and use it for our API tests if we don't specify DATABASES[table_db]['TEST']['NAME']
128 TEST = decouple_config('TEST', default=False, cast=bool)
129 if TEST:
130     for db_key, _ in decouple_config('MATHESAR_DATABASES', cast=Csv(pipe_delim)):
131         DATABASES[db_key]['TEST'] = {'NAME': DATABASES[db_key]['NAME']}
132 
133 
134 # SECURITY WARNING: keep the secret key used in production secret!
135 SECRET_KEY = decouple_config('SECRET_KEY', default="2gr6ud88x=(p855_5nbj_+7^gw-iz&n7ldqv%94mjaecl+b9=4")
136 
137 # SECURITY WARNING: don't run with debug turned on in production!
138 DEBUG = decouple_config('DEBUG', default=False, cast=bool)
139 
140 ALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv(), default=".localhost, 127.0.0.1, [::1]")
141 
142 # Password validation
143 # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
144 
145 AUTH_PASSWORD_VALIDATORS = [
146     {
147         "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
148     },
149     {
150         "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
151     },
152     {
153         "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
154     },
155     {
156         "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
157     },
158 ]
159 
160 # Internationalization
161 # https://docs.djangoproject.com/en/3.1/topics/i18n/
162 
163 LANGUAGE_CODE = "en-us"
164 
165 TIME_ZONE = "UTC"
166 
167 USE_I18N = True
168 
169 USE_L10N = True
170 
171 USE_TZ = True
172 
173 # Static files (CSS, JavaScript, Images)
174 # https://docs.djangoproject.com/en/3.1/howto/static-files/
175 # https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/
176 
177 STATIC_URL = "/static/"
178 
179 # When running with DEBUG=False, the webserver needs to serve files from this location
180 # python manage.py collectstatic has to be run to collect all static files into this location
181 # The files need to served in brotli or gzip compressed format
182 STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
183 
184 # Media files (uploaded by the user)
185 DEFAULT_MEDIA_ROOT = os.path.join(BASE_DIR, '.media/')
186 MEDIA_ROOT = decouple_config('MEDIA_ROOT', default=DEFAULT_MEDIA_ROOT)
187 
188 MEDIA_URL = "/media/"
189 
190 # Update Authentication classes, removed BasicAuthentication
191 # Defaults: https://www.django-rest-framework.org/api-guide/settings/
192 REST_FRAMEWORK = {
193     'DEFAULT_AUTHENTICATION_CLASSES': [
194         'rest_framework.authentication.TokenAuthentication',
195         'rest_framework.authentication.SessionAuthentication'
196     ],
197     'DEFAULT_PERMISSION_CLASSES': [
198         'rest_framework.permissions.IsAuthenticated',
199     ],
200     'DEFAULT_PARSER_CLASSES': [
201         'rest_framework.parsers.JSONParser',
202     ],
203     'DEFAULT_FILTER_BACKENDS': (
204         'django_filters.rest_framework.DjangoFilterBackend',
205         'rest_framework.filters.OrderingFilter',
206     ),
207     'TEST_REQUEST_DEFAULT_FORMAT': 'json',
208     'EXCEPTION_HANDLER':
209         'mathesar.exception_handlers.mathesar_exception_handler',
210     'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'
211 }
212 SPECTACULAR_SETTINGS = {
213     'TITLE': 'Mathesar API',
214     'DESCRIPTION': '',
215     'VERSION': '1.0.0',
216     'SERVE_INCLUDE_SCHEMA': False,
217     'PREPROCESSING_HOOKS': ['config.settings.openapi.custom_preprocessing_hook'],
218     'POSTPROCESSING_HOOKS': [
219         'config.settings.openapi.remove_url_prefix_hook',
220     ],
221     # OTHER SETTINGS
222 }
223 FRIENDLY_ERRORS = {
224     'FIELD_ERRORS': {
225         # By default drf-friendly-errors does contain error codes for ListSerializer type
226         'ListSerializer': {
227             'required': 2007,
228             'null': 2027,
229             'invalid_choice': 2083,
230             'not_a_list': 2123,
231             'empty': 2093
232         },
233         'PermittedPkRelatedField': {
234             'required': 2007,
235             'null': 2027,
236             'does_not_exist': 2151,
237             'incorrect_type': 2161
238         },
239         'PermittedSlugRelatedField': {
240             'required': 2007, 'invalid': 2002, 'null': 2027,
241             'does_not_exist': 2151, 'incorrect_type': 2161
242         },
243     },
244     'EXCEPTION_DICT': {
245         'Http404': 4005
246     }
247 }
248 # Mathesar settings
249 MATHESAR_MODE = decouple_config('MODE', default='PRODUCTION')
250 MATHESAR_UI_BUILD_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/mathesar/')
251 MATHESAR_MANIFEST_LOCATION = os.path.join(MATHESAR_UI_BUILD_LOCATION, 'manifest.json')
252 MATHESAR_CLIENT_DEV_URL = decouple_config(
253     'MATHESAR_CLIENT_DEV_URL',
254     default='http://localhost:3000'
255 )
256 MATHESAR_UI_SOURCE_LOCATION = os.path.join(BASE_DIR, 'mathesar_ui/')
257 MATHESAR_CAPTURE_UNHANDLED_EXCEPTION = decouple_config('CAPTURE_UNHANDLED_EXCEPTION', default=False)
258 MATHESAR_STATIC_NON_CODE_FILES_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/non-code/')
259 
260 # UI source files have to be served by Django in order for static assets to be included during dev mode
261 # https://vitejs.dev/guide/assets.html
262 # https://vitejs.dev/guide/backend-integration.html
263 STATICFILES_DIRS = [MATHESAR_UI_SOURCE_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION] if MATHESAR_MODE == 'DEVELOPMENT' else [MATHESAR_UI_BUILD_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION]
264 STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
265 
266 # Accounts
267 AUTH_USER_MODEL = 'mathesar.User'
268 LOGIN_URL = '/auth/login/'
269 LOGIN_REDIRECT_URL = '/'
270 LOGOUT_REDIRECT_URL = LOGIN_URL
271 DRF_ACCESS_POLICY = {
272     'reusable_conditions': ['mathesar.api.permission_conditions']
273 }
274 # List of Template names that contains additional script tags to be added to the base template
275 BASE_TEMPLATE_ADDITIONAL_SCRIPT_TEMPLATES = []
276 
277 # i18n
278 LANGUAGES = [
279     ('en', 'English'),
280     ('ja', 'Japanese'),
281 ]
282 LOCALE_PATHS = [
283     'translations'
284 ]
285 LANGUAGE_COOKIE_NAME = 'display_language'
286 FALLBACK_LANGUAGE = 'en'
287 
288 SALT_KEY = SECRET_KEY
289
```

Path: `config/settings/openapi.py`
Content:
```
1 def custom_preprocessing_hook(endpoints):
2     prefixes = [
3         "/api/db/v0/databases/",
4         "/api/db/v0/data_files/",
5         "/api/db/v0/schemas/",
6         "/api/db/v0/tables/",
7         "/api/db/v0/links/",
8         "/api/db/v0/queries/",
9         "/api/ui/v0/databases/",
10         "/api/ui/v0/users/",
11         "/api/ui/v0/database_roles/"
12     ]
13     filtered = [(path, path_regex, method, callback) for path, path_regex, method, callback in endpoints if any(path.startswith(prefix) for prefix in prefixes)]
14     return filtered
15 
16 
17 def remove_url_prefix_hook(result, **kwargs):
18     # Remove namespace and version URL prefix from the operation Id of the generated API schema
19     for path, path_info in result['paths'].items():
20         for method, operation in path_info.items():
21             operation_id = operation.get('operationId')
22             if operation_id:
23                 if path.startswith('/api/db/v0/'):
24                     operation['operationId'] = operation_id.replace('db_v0_', '')
25                 elif path.startswith('/api/ui/v0/'):
26                     operation['operationId'] = operation_id.replace('ui_v0_', '')
27 
28     return result
29
```
--- 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/config/settings/common_settings.py b/config/settings/common_settings.py
--- a/config/settings/common_settings.py
+++ b/config/settings/common_settings.py
@@ -42,7 +42,6 @@
     "rest_framework",
     "django_filters",
     "django_property_filter",
-    "drf_spectacular",
     "modernrpc",
     "mathesar",
 ]
@@ -207,18 +206,6 @@
     'TEST_REQUEST_DEFAULT_FORMAT': 'json',
     'EXCEPTION_HANDLER':
         'mathesar.exception_handlers.mathesar_exception_handler',
-    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'
-}
-SPECTACULAR_SETTINGS = {
-    'TITLE': 'Mathesar API',
-    'DESCRIPTION': '',
-    'VERSION': '1.0.0',
-    'SERVE_INCLUDE_SCHEMA': False,
-    'PREPROCESSING_HOOKS': ['config.settings.openapi.custom_preprocessing_hook'],
-    'POSTPROCESSING_HOOKS': [
-        'config.settings.openapi.remove_url_prefix_hook',
-    ],
-    # OTHER SETTINGS
 }
 FRIENDLY_ERRORS = {
     'FIELD_ERRORS': {
diff --git a/config/settings/openapi.py b/config/settings/openapi.py
deleted file mode 100644
--- a/config/settings/openapi.py
+++ /dev/null
@@ -1,28 +0,0 @@
-def custom_preprocessing_hook(endpoints):
-    prefixes = [
-        "/api/db/v0/databases/",
-        "/api/db/v0/data_files/",
-        "/api/db/v0/schemas/",
-        "/api/db/v0/tables/",
-        "/api/db/v0/links/",
-        "/api/db/v0/queries/",
-        "/api/ui/v0/databases/",
-        "/api/ui/v0/users/",
-        "/api/ui/v0/database_roles/"
-    ]
-    filtered = [(path, path_regex, method, callback) for path, path_regex, method, callback in endpoints if any(path.startswith(prefix) for prefix in prefixes)]
-    return filtered
-
-
-def remove_url_prefix_hook(result, **kwargs):
-    # Remove namespace and version URL prefix from the operation Id of the generated API schema
-    for path, path_info in result['paths'].items():
-        for method, operation in path_info.items():
-            operation_id = operation.get('operationId')
-            if operation_id:
-                if path.startswith('/api/db/v0/'):
-                    operation['operationId'] = operation_id.replace('db_v0_', '')
-                elif path.startswith('/api/ui/v0/'):
-                    operation['operationId'] = operation_id.replace('ui_v0_', '')
-
-    return result

{"golden_diff": "diff --git a/config/settings/common_settings.py b/config/settings/common_settings.py\n--- a/config/settings/common_settings.py\n+++ b/config/settings/common_settings.py\n@@ -42,7 +42,6 @@\n     \"rest_framework\",\n     \"django_filters\",\n     \"django_property_filter\",\n-    \"drf_spectacular\",\n     \"modernrpc\",\n     \"mathesar\",\n ]\n@@ -207,18 +206,6 @@\n     'TEST_REQUEST_DEFAULT_FORMAT': 'json',\n     'EXCEPTION_HANDLER':\n         'mathesar.exception_handlers.mathesar_exception_handler',\n-    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'\n-}\n-SPECTACULAR_SETTINGS = {\n-    'TITLE': 'Mathesar API',\n-    'DESCRIPTION': '',\n-    'VERSION': '1.0.0',\n-    'SERVE_INCLUDE_SCHEMA': False,\n-    'PREPROCESSING_HOOKS': ['config.settings.openapi.custom_preprocessing_hook'],\n-    'POSTPROCESSING_HOOKS': [\n-        'config.settings.openapi.remove_url_prefix_hook',\n-    ],\n-    # OTHER SETTINGS\n }\n FRIENDLY_ERRORS = {\n     'FIELD_ERRORS': {\ndiff --git a/config/settings/openapi.py b/config/settings/openapi.py\ndeleted file mode 100644\n--- a/config/settings/openapi.py\n+++ /dev/null\n@@ -1,28 +0,0 @@\n-def custom_preprocessing_hook(endpoints):\n-    prefixes = [\n-        \"/api/db/v0/databases/\",\n-        \"/api/db/v0/data_files/\",\n-        \"/api/db/v0/schemas/\",\n-        \"/api/db/v0/tables/\",\n-        \"/api/db/v0/links/\",\n-        \"/api/db/v0/queries/\",\n-        \"/api/ui/v0/databases/\",\n-        \"/api/ui/v0/users/\",\n-        \"/api/ui/v0/database_roles/\"\n-    ]\n-    filtered = [(path, path_regex, method, callback) for path, path_regex, method, callback in endpoints if any(path.startswith(prefix) for prefix in prefixes)]\n-    return filtered\n-\n-\n-def remove_url_prefix_hook(result, **kwargs):\n-    # Remove namespace and version URL prefix from the operation Id of the generated API schema\n-    for path, path_info in result['paths'].items():\n-        for method, operation in path_info.items():\n-            operation_id = operation.get('operationId')\n-            if operation_id:\n-                if path.startswith('/api/db/v0/'):\n-                    operation['operationId'] = operation_id.replace('db_v0_', '')\n-                elif path.startswith('/api/ui/v0/'):\n-                    operation['operationId'] = operation_id.replace('ui_v0_', '')\n-\n-    return result\n", "issue": "Remove unused API docs cruft\nSince we're moving to the RPC endpoint style, we need to remove the remaining pieces of the REST API documentation infrastructure.\n", "before_files": [{"content": "\"\"\"\nBase settings to build other settings files upon.\n\nGenerated by 'django-admin startproject' using Django 3.1.7.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/3.1/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/3.1/ref/settings/\n\"\"\"\n\nimport os\nfrom pathlib import Path\n\nfrom decouple import Csv, config as decouple_config\nfrom dj_database_url import parse as db_url\n\n\n# We use a 'tuple' with pipes as delimiters as decople naively splits the global\n# variables on commas when casting to Csv()\ndef pipe_delim(pipe_string):\n    # Remove opening and closing brackets\n    pipe_string = pipe_string[1:-1]\n    # Split on pipe delim\n    return pipe_string.split(\"|\")\n\n\n# Build paths inside the project like this: BASE_DIR / 'subdir'.\nBASE_DIR = Path(__file__).resolve().parent.parent.parent\n\n# Application definition\n\nINSTALLED_APPS = [\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"whitenoise.runserver_nostatic\",\n    \"django.contrib.staticfiles\",\n    \"rest_framework\",\n    \"django_filters\",\n    \"django_property_filter\",\n    \"drf_spectacular\",\n    \"modernrpc\",\n    \"mathesar\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"whitenoise.middleware.WhiteNoiseMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.locale.LocaleMiddleware\",\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    \"mathesar.middleware.CursorClosedHandlerMiddleware\",\n    \"mathesar.middleware.PasswordChangeNeededMiddleware\",\n    'django_userforeignkey.middleware.UserForeignKeyMiddleware',\n    'django_request_cache.middleware.RequestCacheMiddleware',\n]\n\nROOT_URLCONF = \"config.urls\"\n\nMODERNRPC_METHODS_MODULES = [\n    'mathesar.rpc.connections'\n]\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"DIRS\": [],\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"config.context_processors.frontend_settings\",\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                \"mathesar.template_context_processors.base_template_extensions.script_extension_templates\"\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = \"config.wsgi.application\"\n\n# Database\n# https://docs.djangoproject.com/en/3.1/ref/settings/#databases\n\n# TODO: Add to documentation that database keys should not be than 128 characters.\n\n# MATHESAR_DATABASES should be of the form '({db_name}|{db_url}), ({db_name}|{db_url})'\n# See pipe_delim above for why we use pipes as delimiters\nDATABASES = {\n    db_key: db_url(url_string)\n    for db_key, url_string in decouple_config('MATHESAR_DATABASES', default='', cast=Csv(pipe_delim))\n}\n\n# POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST & POSTGRES_PORT are required env variables for forming a pg connection string for the django database\n# lack of any one of these will result in the internal django database to be sqlite.\nPOSTGRES_DB = decouple_config('POSTGRES_DB', default=None)\nPOSTGRES_USER = decouple_config('POSTGRES_USER', default=None)\nPOSTGRES_PASSWORD = decouple_config('POSTGRES_PASSWORD', default=None)\nPOSTGRES_HOST = decouple_config('POSTGRES_HOST', default=None)\nPOSTGRES_PORT = decouple_config('POSTGRES_PORT', default=None)\n\nif POSTGRES_DB and POSTGRES_USER and POSTGRES_PASSWORD and POSTGRES_HOST and POSTGRES_PORT:\n    DATABASES['default'] = db_url(f'postgres://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}')\nelse:\n    DATABASES['default'] = db_url('sqlite:///db.sqlite3')\n\nfor db_key, db_dict in DATABASES.items():\n    # Engine should be '.postgresql' or '.postgresql_psycopg2' for all db(s),\n    # however for the internal 'default' db 'sqlite3' can be used.\n    if not db_dict['ENGINE'].startswith('django.db.backends.postgresql') and db_key != 'default':\n        raise ValueError(\n            f\"{db_key} is not a PostgreSQL database. \"\n            f\"{db_dict['ENGINE']} found for {db_key}'s engine.\"\n        )\n\n# pytest-django will create a new database named 'test_{DATABASES[table_db]['NAME']}'\n# and use it for our API tests if we don't specify DATABASES[table_db]['TEST']['NAME']\nTEST = decouple_config('TEST', default=False, cast=bool)\nif TEST:\n    for db_key, _ in decouple_config('MATHESAR_DATABASES', cast=Csv(pipe_delim)):\n        DATABASES[db_key]['TEST'] = {'NAME': DATABASES[db_key]['NAME']}\n\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = decouple_config('SECRET_KEY', default=\"2gr6ud88x=(p855_5nbj_+7^gw-iz&n7ldqv%94mjaecl+b9=4\")\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = decouple_config('DEBUG', default=False, cast=bool)\n\nALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv(), default=\".localhost, 127.0.0.1, [::1]\")\n\n# Password validation\n# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        \"NAME\": \"django.contrib.auth.password_validation.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\n# Internationalization\n# https://docs.djangoproject.com/en/3.1/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/3.1/howto/static-files/\n# https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/\n\nSTATIC_URL = \"/static/\"\n\n# When running with DEBUG=False, the webserver needs to serve files from this location\n# python manage.py collectstatic has to be run to collect all static files into this location\n# The files need to served in brotli or gzip compressed format\nSTATIC_ROOT = os.path.join(BASE_DIR, 'static/')\n\n# Media files (uploaded by the user)\nDEFAULT_MEDIA_ROOT = os.path.join(BASE_DIR, '.media/')\nMEDIA_ROOT = decouple_config('MEDIA_ROOT', default=DEFAULT_MEDIA_ROOT)\n\nMEDIA_URL = \"/media/\"\n\n# Update Authentication classes, removed BasicAuthentication\n# Defaults: https://www.django-rest-framework.org/api-guide/settings/\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication'\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n    'DEFAULT_PARSER_CLASSES': [\n        'rest_framework.parsers.JSONParser',\n    ],\n    'DEFAULT_FILTER_BACKENDS': (\n        'django_filters.rest_framework.DjangoFilterBackend',\n        'rest_framework.filters.OrderingFilter',\n    ),\n    'TEST_REQUEST_DEFAULT_FORMAT': 'json',\n    'EXCEPTION_HANDLER':\n        'mathesar.exception_handlers.mathesar_exception_handler',\n    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'\n}\nSPECTACULAR_SETTINGS = {\n    'TITLE': 'Mathesar API',\n    'DESCRIPTION': '',\n    'VERSION': '1.0.0',\n    'SERVE_INCLUDE_SCHEMA': False,\n    'PREPROCESSING_HOOKS': ['config.settings.openapi.custom_preprocessing_hook'],\n    'POSTPROCESSING_HOOKS': [\n        'config.settings.openapi.remove_url_prefix_hook',\n    ],\n    # OTHER SETTINGS\n}\nFRIENDLY_ERRORS = {\n    'FIELD_ERRORS': {\n        # By default drf-friendly-errors does contain error codes for ListSerializer type\n        'ListSerializer': {\n            'required': 2007,\n            'null': 2027,\n            'invalid_choice': 2083,\n            'not_a_list': 2123,\n            'empty': 2093\n        },\n        'PermittedPkRelatedField': {\n            'required': 2007,\n            'null': 2027,\n            'does_not_exist': 2151,\n            'incorrect_type': 2161\n        },\n        'PermittedSlugRelatedField': {\n            'required': 2007, 'invalid': 2002, 'null': 2027,\n            'does_not_exist': 2151, 'incorrect_type': 2161\n        },\n    },\n    'EXCEPTION_DICT': {\n        'Http404': 4005\n    }\n}\n# Mathesar settings\nMATHESAR_MODE = decouple_config('MODE', default='PRODUCTION')\nMATHESAR_UI_BUILD_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/mathesar/')\nMATHESAR_MANIFEST_LOCATION = os.path.join(MATHESAR_UI_BUILD_LOCATION, 'manifest.json')\nMATHESAR_CLIENT_DEV_URL = decouple_config(\n    'MATHESAR_CLIENT_DEV_URL',\n    default='http://localhost:3000'\n)\nMATHESAR_UI_SOURCE_LOCATION = os.path.join(BASE_DIR, 'mathesar_ui/')\nMATHESAR_CAPTURE_UNHANDLED_EXCEPTION = decouple_config('CAPTURE_UNHANDLED_EXCEPTION', default=False)\nMATHESAR_STATIC_NON_CODE_FILES_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/non-code/')\n\n# UI source files have to be served by Django in order for static assets to be included during dev mode\n# https://vitejs.dev/guide/assets.html\n# https://vitejs.dev/guide/backend-integration.html\nSTATICFILES_DIRS = [MATHESAR_UI_SOURCE_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION] if MATHESAR_MODE == 'DEVELOPMENT' else [MATHESAR_UI_BUILD_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION]\nSTATICFILES_STORAGE = \"whitenoise.storage.CompressedManifestStaticFilesStorage\"\n\n# Accounts\nAUTH_USER_MODEL = 'mathesar.User'\nLOGIN_URL = '/auth/login/'\nLOGIN_REDIRECT_URL = '/'\nLOGOUT_REDIRECT_URL = LOGIN_URL\nDRF_ACCESS_POLICY = {\n    'reusable_conditions': ['mathesar.api.permission_conditions']\n}\n# List of Template names that contains additional script tags to be added to the base template\nBASE_TEMPLATE_ADDITIONAL_SCRIPT_TEMPLATES = []\n\n# i18n\nLANGUAGES = [\n    ('en', 'English'),\n    ('ja', 'Japanese'),\n]\nLOCALE_PATHS = [\n    'translations'\n]\nLANGUAGE_COOKIE_NAME = 'display_language'\nFALLBACK_LANGUAGE = 'en'\n\nSALT_KEY = SECRET_KEY\n", "path": "config/settings/common_settings.py"}, {"content": "def custom_preprocessing_hook(endpoints):\n    prefixes = [\n        \"/api/db/v0/databases/\",\n        \"/api/db/v0/data_files/\",\n        \"/api/db/v0/schemas/\",\n        \"/api/db/v0/tables/\",\n        \"/api/db/v0/links/\",\n        \"/api/db/v0/queries/\",\n        \"/api/ui/v0/databases/\",\n        \"/api/ui/v0/users/\",\n        \"/api/ui/v0/database_roles/\"\n    ]\n    filtered = [(path, path_regex, method, callback) for path, path_regex, method, callback in endpoints if any(path.startswith(prefix) for prefix in prefixes)]\n    return filtered\n\n\ndef remove_url_prefix_hook(result, **kwargs):\n    # Remove namespace and version URL prefix from the operation Id of the generated API schema\n    for path, path_info in result['paths'].items():\n        for method, operation in path_info.items():\n            operation_id = operation.get('operationId')\n            if operation_id:\n                if path.startswith('/api/db/v0/'):\n                    operation['operationId'] = operation_id.replace('db_v0_', '')\n                elif path.startswith('/api/ui/v0/'):\n                    operation['operationId'] = operation_id.replace('ui_v0_', '')\n\n    return result\n", "path": "config/settings/openapi.py"}], "after_files": [{"content": "\"\"\"\nBase settings to build other settings files upon.\n\nGenerated by 'django-admin startproject' using Django 3.1.7.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/3.1/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/3.1/ref/settings/\n\"\"\"\n\nimport os\nfrom pathlib import Path\n\nfrom decouple import Csv, config as decouple_config\nfrom dj_database_url import parse as db_url\n\n\n# We use a 'tuple' with pipes as delimiters as decople naively splits the global\n# variables on commas when casting to Csv()\ndef pipe_delim(pipe_string):\n    # Remove opening and closing brackets\n    pipe_string = pipe_string[1:-1]\n    # Split on pipe delim\n    return pipe_string.split(\"|\")\n\n\n# Build paths inside the project like this: BASE_DIR / 'subdir'.\nBASE_DIR = Path(__file__).resolve().parent.parent.parent\n\n# Application definition\n\nINSTALLED_APPS = [\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"whitenoise.runserver_nostatic\",\n    \"django.contrib.staticfiles\",\n    \"rest_framework\",\n    \"django_filters\",\n    \"django_property_filter\",\n    \"modernrpc\",\n    \"mathesar\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"whitenoise.middleware.WhiteNoiseMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.locale.LocaleMiddleware\",\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    \"mathesar.middleware.CursorClosedHandlerMiddleware\",\n    \"mathesar.middleware.PasswordChangeNeededMiddleware\",\n    'django_userforeignkey.middleware.UserForeignKeyMiddleware',\n    'django_request_cache.middleware.RequestCacheMiddleware',\n]\n\nROOT_URLCONF = \"config.urls\"\n\nMODERNRPC_METHODS_MODULES = [\n    'mathesar.rpc.connections'\n]\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"DIRS\": [],\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"config.context_processors.frontend_settings\",\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                \"mathesar.template_context_processors.base_template_extensions.script_extension_templates\"\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = \"config.wsgi.application\"\n\n# Database\n# https://docs.djangoproject.com/en/3.1/ref/settings/#databases\n\n# TODO: Add to documentation that database keys should not be than 128 characters.\n\n# MATHESAR_DATABASES should be of the form '({db_name}|{db_url}), ({db_name}|{db_url})'\n# See pipe_delim above for why we use pipes as delimiters\nDATABASES = {\n    db_key: db_url(url_string)\n    for db_key, url_string in decouple_config('MATHESAR_DATABASES', default='', cast=Csv(pipe_delim))\n}\n\n# POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST & POSTGRES_PORT are required env variables for forming a pg connection string for the django database\n# lack of any one of these will result in the internal django database to be sqlite.\nPOSTGRES_DB = decouple_config('POSTGRES_DB', default=None)\nPOSTGRES_USER = decouple_config('POSTGRES_USER', default=None)\nPOSTGRES_PASSWORD = decouple_config('POSTGRES_PASSWORD', default=None)\nPOSTGRES_HOST = decouple_config('POSTGRES_HOST', default=None)\nPOSTGRES_PORT = decouple_config('POSTGRES_PORT', default=None)\n\nif POSTGRES_DB and POSTGRES_USER and POSTGRES_PASSWORD and POSTGRES_HOST and POSTGRES_PORT:\n    DATABASES['default'] = db_url(f'postgres://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}')\nelse:\n    DATABASES['default'] = db_url('sqlite:///db.sqlite3')\n\nfor db_key, db_dict in DATABASES.items():\n    # Engine should be '.postgresql' or '.postgresql_psycopg2' for all db(s),\n    # however for the internal 'default' db 'sqlite3' can be used.\n    if not db_dict['ENGINE'].startswith('django.db.backends.postgresql') and db_key != 'default':\n        raise ValueError(\n            f\"{db_key} is not a PostgreSQL database. \"\n            f\"{db_dict['ENGINE']} found for {db_key}'s engine.\"\n        )\n\n# pytest-django will create a new database named 'test_{DATABASES[table_db]['NAME']}'\n# and use it for our API tests if we don't specify DATABASES[table_db]['TEST']['NAME']\nTEST = decouple_config('TEST', default=False, cast=bool)\nif TEST:\n    for db_key, _ in decouple_config('MATHESAR_DATABASES', cast=Csv(pipe_delim)):\n        DATABASES[db_key]['TEST'] = {'NAME': DATABASES[db_key]['NAME']}\n\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = decouple_config('SECRET_KEY', default=\"2gr6ud88x=(p855_5nbj_+7^gw-iz&n7ldqv%94mjaecl+b9=4\")\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = decouple_config('DEBUG', default=False, cast=bool)\n\nALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv(), default=\".localhost, 127.0.0.1, [::1]\")\n\n# Password validation\n# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        \"NAME\": \"django.contrib.auth.password_validation.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\n# Internationalization\n# https://docs.djangoproject.com/en/3.1/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/3.1/howto/static-files/\n# https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/\n\nSTATIC_URL = \"/static/\"\n\n# When running with DEBUG=False, the webserver needs to serve files from this location\n# python manage.py collectstatic has to be run to collect all static files into this location\n# The files need to served in brotli or gzip compressed format\nSTATIC_ROOT = os.path.join(BASE_DIR, 'static/')\n\n# Media files (uploaded by the user)\nDEFAULT_MEDIA_ROOT = os.path.join(BASE_DIR, '.media/')\nMEDIA_ROOT = decouple_config('MEDIA_ROOT', default=DEFAULT_MEDIA_ROOT)\n\nMEDIA_URL = \"/media/\"\n\n# Update Authentication classes, removed BasicAuthentication\n# Defaults: https://www.django-rest-framework.org/api-guide/settings/\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication'\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n    'DEFAULT_PARSER_CLASSES': [\n        'rest_framework.parsers.JSONParser',\n    ],\n    'DEFAULT_FILTER_BACKENDS': (\n        'django_filters.rest_framework.DjangoFilterBackend',\n        'rest_framework.filters.OrderingFilter',\n    ),\n    'TEST_REQUEST_DEFAULT_FORMAT': 'json',\n    'EXCEPTION_HANDLER':\n        'mathesar.exception_handlers.mathesar_exception_handler',\n}\nFRIENDLY_ERRORS = {\n    'FIELD_ERRORS': {\n        # By default drf-friendly-errors does contain error codes for ListSerializer type\n        'ListSerializer': {\n            'required': 2007,\n            'null': 2027,\n            'invalid_choice': 2083,\n            'not_a_list': 2123,\n            'empty': 2093\n        },\n        'PermittedPkRelatedField': {\n            'required': 2007,\n            'null': 2027,\n            'does_not_exist': 2151,\n            'incorrect_type': 2161\n        },\n        'PermittedSlugRelatedField': {\n            'required': 2007, 'invalid': 2002, 'null': 2027,\n            'does_not_exist': 2151, 'incorrect_type': 2161\n        },\n    },\n    'EXCEPTION_DICT': {\n        'Http404': 4005\n    }\n}\n# Mathesar settings\nMATHESAR_MODE = decouple_config('MODE', default='PRODUCTION')\nMATHESAR_UI_BUILD_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/mathesar/')\nMATHESAR_MANIFEST_LOCATION = os.path.join(MATHESAR_UI_BUILD_LOCATION, 'manifest.json')\nMATHESAR_CLIENT_DEV_URL = decouple_config(\n    'MATHESAR_CLIENT_DEV_URL',\n    default='http://localhost:3000'\n)\nMATHESAR_UI_SOURCE_LOCATION = os.path.join(BASE_DIR, 'mathesar_ui/')\nMATHESAR_CAPTURE_UNHANDLED_EXCEPTION = decouple_config('CAPTURE_UNHANDLED_EXCEPTION', default=False)\nMATHESAR_STATIC_NON_CODE_FILES_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/non-code/')\n\n# UI source files have to be served by Django in order for static assets to be included during dev mode\n# https://vitejs.dev/guide/assets.html\n# https://vitejs.dev/guide/backend-integration.html\nSTATICFILES_DIRS = [MATHESAR_UI_SOURCE_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION] if MATHESAR_MODE == 'DEVELOPMENT' else [MATHESAR_UI_BUILD_LOCATION, MATHESAR_STATIC_NON_CODE_FILES_LOCATION]\nSTATICFILES_STORAGE = \"whitenoise.storage.CompressedManifestStaticFilesStorage\"\n\n# Accounts\nAUTH_USER_MODEL = 'mathesar.User'\nLOGIN_URL = '/auth/login/'\nLOGIN_REDIRECT_URL = '/'\nLOGOUT_REDIRECT_URL = LOGIN_URL\nDRF_ACCESS_POLICY = {\n    'reusable_conditions': ['mathesar.api.permission_conditions']\n}\n# List of Template names that contains additional script tags to be added to the base template\nBASE_TEMPLATE_ADDITIONAL_SCRIPT_TEMPLATES = []\n\n# i18n\nLANGUAGES = [\n    ('en', 'English'),\n    ('ja', 'Japanese'),\n]\nLOCALE_PATHS = [\n    'translations'\n]\nLANGUAGE_COOKIE_NAME = 'display_language'\nFALLBACK_LANGUAGE = 'en'\n\nSALT_KEY = SECRET_KEY\n", "path": "config/settings/common_settings.py"}, {"content": null, "path": "config/settings/openapi.py"}]}