We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add a Docker image containing the Mathesar server along with a Postgres server
## Problem
The current docker image requires the user to already have a Postgres server running on their machine. This is a hassle for someone looking to try out Matheasar quickly.

## Proposed solution
Provide a docker image containing a Postgres server along with the Mathesar server




--- 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     "mathesar",
47 ]
48 
49 MIDDLEWARE = [
50     "django.middleware.security.SecurityMiddleware",
51     "whitenoise.middleware.WhiteNoiseMiddleware",
52     "django.contrib.sessions.middleware.SessionMiddleware",
53     "django.middleware.common.CommonMiddleware",
54     "django.middleware.csrf.CsrfViewMiddleware",
55     "django.contrib.auth.middleware.AuthenticationMiddleware",
56     "django.contrib.messages.middleware.MessageMiddleware",
57     "django.middleware.clickjacking.XFrameOptionsMiddleware",
58     "mathesar.middleware.CursorClosedHandlerMiddleware",
59     "mathesar.middleware.PasswordChangeNeededMiddleware",
60     'django_userforeignkey.middleware.UserForeignKeyMiddleware',
61     'django_request_cache.middleware.RequestCacheMiddleware',
62 ]
63 
64 ROOT_URLCONF = "config.urls"
65 
66 TEMPLATES = [
67     {
68         "BACKEND": "django.template.backends.django.DjangoTemplates",
69         "DIRS": [],
70         "APP_DIRS": True,
71         "OPTIONS": {
72             "context_processors": [
73                 "config.context_processors.frontend_settings",
74                 "django.template.context_processors.debug",
75                 "django.template.context_processors.request",
76                 "django.contrib.auth.context_processors.auth",
77                 "django.contrib.messages.context_processors.messages",
78                 "mathesar.template_context_processors.base_template_extensions.script_extension_templates"
79             ],
80         },
81     },
82 ]
83 
84 WSGI_APPLICATION = "config.wsgi.application"
85 
86 # Database
87 # https://docs.djangoproject.com/en/3.1/ref/settings/#databases
88 
89 # TODO: Add to documentation that database keys should not be than 128 characters.
90 
91 # MATHESAR_DATABASES should be of the form '({db_name}|{db_url}), ({db_name}|{db_url})'
92 # See pipe_delim above for why we use pipes as delimiters
93 DATABASES = {
94     db_key: db_url(url_string)
95     for db_key, url_string in decouple_config('MATHESAR_DATABASES', cast=Csv(pipe_delim))
96 }
97 
98 DATABASES[decouple_config('DJANGO_DATABASE_KEY', default="default")] = decouple_config('DJANGO_DATABASE_URL', cast=db_url, default='sqlite:///db.sqlite3')
99 
100 for db_key, db_dict in DATABASES.items():
101     # Engine should be '.postgresql' or '.postgresql_psycopg2' for all db(s),
102     # however for the internal 'default' db 'sqlite3' can be used.
103     if not db_dict['ENGINE'].startswith('django.db.backends.postgresql') and db_key != 'default':
104         raise ValueError(
105             f"{db_key} is not a PostgreSQL database. "
106             f"{db_dict['ENGINE']} found for {db_key}'s engine."
107         )
108 
109 # pytest-django will create a new database named 'test_{DATABASES[table_db]['NAME']}'
110 # and use it for our API tests if we don't specify DATABASES[table_db]['TEST']['NAME']
111 TEST = decouple_config('TEST', default=False, cast=bool)
112 if TEST:
113     for db_key, _ in decouple_config('MATHESAR_DATABASES', cast=Csv(pipe_delim)):
114         DATABASES[db_key]['TEST'] = {'NAME': DATABASES[db_key]['NAME']}
115 
116 
117 # SECURITY WARNING: keep the secret key used in production secret!
118 SECRET_KEY = decouple_config('SECRET_KEY')
119 
120 # SECURITY WARNING: don't run with debug turned on in production!
121 DEBUG = decouple_config('DEBUG', default=False, cast=bool)
122 
123 ALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv())
124 
125 # Password validation
126 # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
127 
128 AUTH_PASSWORD_VALIDATORS = [
129     {
130         "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
131     },
132     {
133         "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
134     },
135     {
136         "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
137     },
138     {
139         "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
140     },
141 ]
142 
143 # Internationalization
144 # https://docs.djangoproject.com/en/3.1/topics/i18n/
145 
146 LANGUAGE_CODE = "en-us"
147 
148 TIME_ZONE = "UTC"
149 
150 USE_I18N = True
151 
152 USE_L10N = True
153 
154 USE_TZ = True
155 
156 # Static files (CSS, JavaScript, Images)
157 # https://docs.djangoproject.com/en/3.1/howto/static-files/
158 # https://docs.djangoproject.com/en/3.1/ref/contrib/staticfiles/
159 
160 STATIC_URL = "/static/"
161 
162 # When running with DEBUG=False, the webserver needs to serve files from this location
163 # python manage.py collectstatic has to be run to collect all static files into this location
164 # The files need to served in brotli or gzip compressed format
165 STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
166 
167 # Media files (uploaded by the user)
168 DEFAULT_MEDIA_ROOT = os.path.join(BASE_DIR, '.media/')
169 MEDIA_ROOT = decouple_config('MEDIA_ROOT', default=DEFAULT_MEDIA_ROOT)
170 
171 MEDIA_URL = "/media/"
172 
173 # Update Authentication classes, removed BasicAuthentication
174 # Defaults: https://www.django-rest-framework.org/api-guide/settings/
175 REST_FRAMEWORK = {
176     'DEFAULT_AUTHENTICATION_CLASSES': [
177         'rest_framework.authentication.TokenAuthentication',
178         'rest_framework.authentication.SessionAuthentication'
179     ],
180     'DEFAULT_PERMISSION_CLASSES': [
181         'rest_framework.permissions.IsAuthenticated',
182     ],
183     'DEFAULT_FILTER_BACKENDS': (
184         'django_filters.rest_framework.DjangoFilterBackend',
185         'rest_framework.filters.OrderingFilter',
186     ),
187     'TEST_REQUEST_DEFAULT_FORMAT': 'json',
188     'EXCEPTION_HANDLER':
189         'mathesar.exception_handlers.mathesar_exception_handler',
190     'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'
191 }
192 SPECTACULAR_SETTINGS = {
193     'TITLE': 'Mathesar API',
194     'DESCRIPTION': '',
195     'VERSION': '1.0.0',
196     'SERVE_INCLUDE_SCHEMA': False,
197     'PREPROCESSING_HOOKS': ['config.settings.openapi.custom_preprocessing_hook'],
198     'POSTPROCESSING_HOOKS': [
199         'config.settings.openapi.remove_url_prefix_hook',
200     ],
201     # OTHER SETTINGS
202 }
203 FRIENDLY_ERRORS = {
204     'FIELD_ERRORS': {
205         # By default drf-friendly-errors does contain error codes for ListSerializer type
206         'ListSerializer': {
207             'required': 2007,
208             'null': 2027,
209             'invalid_choice': 2083,
210             'not_a_list': 2123,
211             'empty': 2093
212         },
213         'PermittedPkRelatedField': {
214             'required': 2007,
215             'null': 2027,
216             'does_not_exist': 2151,
217             'incorrect_type': 2161
218         },
219         'PermittedSlugRelatedField': {
220             'required': 2007, 'invalid': 2002, 'null': 2027,
221             'does_not_exist': 2151, 'incorrect_type': 2161
222         },
223     },
224     'EXCEPTION_DICT': {
225         'Http404': 4005
226     }
227 }
228 # Mathesar settings
229 MATHESAR_MODE = decouple_config('MODE', default='PRODUCTION')
230 MATHESAR_UI_BUILD_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/mathesar/')
231 MATHESAR_MANIFEST_LOCATION = os.path.join(MATHESAR_UI_BUILD_LOCATION, 'manifest.json')
232 MATHESAR_CLIENT_DEV_URL = 'http://localhost:3000'
233 MATHESAR_UI_SOURCE_LOCATION = os.path.join(BASE_DIR, 'mathesar_ui/')
234 MATHESAR_CAPTURE_UNHANDLED_EXCEPTION = decouple_config('CAPTURE_UNHANDLED_EXCEPTION', default=False)
235 MATHESAR_STATIC_NON_CODE_FILES_LOCATION = os.path.join(BASE_DIR, 'mathesar/static/non-code/')
236 
237 # UI source files have to be served by Django in order for static assets to be included during dev mode
238 # https://vitejs.dev/guide/assets.html
239 # https://vitejs.dev/guide/backend-integration.html
240 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]
241 STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
242 
243 # Accounts
244 AUTH_USER_MODEL = 'mathesar.User'
245 LOGIN_URL = '/auth/login/'
246 LOGIN_REDIRECT_URL = '/'
247 LOGOUT_REDIRECT_URL = LOGIN_URL
248 DRF_ACCESS_POLICY = {
249     'reusable_conditions': ['mathesar.api.permission_conditions']
250 }
251 # List of Template names that contains additional script tags to be added to the base template
252 BASE_TEMPLATE_ADDITIONAL_SCRIPT_TEMPLATES = []
253
```

Path: `db/install.py`
Content:
```
1 from psycopg.errors import InsufficientPrivilege
2 from sqlalchemy import text
3 from sqlalchemy.exc import OperationalError, ProgrammingError
4 
5 from db import engine
6 from db.sql import install as sql_install
7 from db.types import install as types_install
8 
9 
10 def install_mathesar(
11         database_name, username, password, hostname, port, skip_confirm
12 ):
13     """Create database and install Mathesar on it."""
14     user_db_engine = engine.create_future_engine(
15         username, password, hostname, database_name, port,
16         connect_args={"connect_timeout": 10}
17     )
18     try:
19         user_db_engine.connect()
20         print(f"Installing Mathesar on preexisting PostgreSQL database {database_name} at host {hostname}...")
21         sql_install.install(user_db_engine)
22         types_install.install_mathesar_on_database(user_db_engine)
23         user_db_engine.dispose()
24     except OperationalError:
25         database_created = _create_database(
26             database_name=database_name,
27             hostname=hostname,
28             username=username,
29             password=password,
30             port=port,
31             skip_confirm=skip_confirm
32         )
33         if database_created:
34             print(f"Installing Mathesar on PostgreSQL database {database_name} at host {hostname}...")
35             sql_install.install(user_db_engine)
36             types_install.install_mathesar_on_database(user_db_engine)
37             user_db_engine.dispose()
38         else:
39             print(f"Skipping installing on DB with key {database_name}.")
40 
41 
42 def _create_database(database_name, hostname, username, password, port, skip_confirm=True):
43     if skip_confirm is True:
44         create_database = "y"
45     else:
46         create_database = input(
47             f"Create a new Database called {database_name}? (y/n) > "
48         )
49     if create_database.lower() in ["y", "yes"]:
50         # We need to connect to an existing database inorder to create a new Database.
51         # So we use the default Database `postgres` that comes with postgres.
52         # TODO Throw correct error when the default postgres database does not exists(which is very rare but still possible)
53         root_database = "postgres"
54         root_db_engine = engine.create_future_engine(
55             username, password, hostname, root_database, port,
56             connect_args={"connect_timeout": 10}
57         )
58         try:
59             with root_db_engine.connect() as conn:
60                 conn.execution_options(isolation_level="AUTOCOMMIT")
61                 conn.execute(text(f'CREATE DATABASE "{database_name}"'))
62             root_db_engine.dispose()
63             print(f"Created DB is {database_name}.")
64             return True
65         except ProgrammingError as e:
66             if isinstance(e.orig, InsufficientPrivilege):
67                 print(f"Database {database_name} could not be created due to Insufficient Privilege")
68                 return False
69         except Exception:
70             print(f"Database {database_name} could not be created!")
71             return False
72     else:
73         print(f"Database {database_name} not created!")
74         return False
75
```
--- 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
@@ -115,12 +115,12 @@
 
 
 # SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = decouple_config('SECRET_KEY')
+SECRET_KEY = decouple_config('SECRET_KEY', default="2gr6ud88x=(p855_5nbj_+7^gw-iz&n7ldqv%94mjaecl+b9=4")
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = decouple_config('DEBUG', default=False, cast=bool)
 
-ALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv())
+ALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv(), default=".localhost, 127.0.0.1, [::1]")
 
 # Password validation
 # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
diff --git a/db/install.py b/db/install.py
--- a/db/install.py
+++ b/db/install.py
@@ -48,7 +48,7 @@
         )
     if create_database.lower() in ["y", "yes"]:
         # We need to connect to an existing database inorder to create a new Database.
-        # So we use the default Database `postgres` that comes with postgres.
+        # So we use the default database `postgres` that comes with postgres.
         # TODO Throw correct error when the default postgres database does not exists(which is very rare but still possible)
         root_database = "postgres"
         root_db_engine = engine.create_future_engine(

{"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@@ -115,12 +115,12 @@\n \n \n # SECURITY WARNING: keep the secret key used in production secret!\n-SECRET_KEY = decouple_config('SECRET_KEY')\n+SECRET_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!\n DEBUG = decouple_config('DEBUG', default=False, cast=bool)\n \n-ALLOWED_HOSTS = decouple_config('ALLOWED_HOSTS', cast=Csv())\n+ALLOWED_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\ndiff --git a/db/install.py b/db/install.py\n--- a/db/install.py\n+++ b/db/install.py\n@@ -48,7 +48,7 @@\n         )\n     if create_database.lower() in [\"y\", \"yes\"]:\n         # We need to connect to an existing database inorder to create a new Database.\n-        # So we use the default Database `postgres` that comes with postgres.\n+        # So we use the default database `postgres` that comes with postgres.\n         # TODO Throw correct error when the default postgres database does not exists(which is very rare but still possible)\n         root_database = \"postgres\"\n         root_db_engine = engine.create_future_engine(\n", "issue": "Add a Docker image containing the Mathesar server along with a Postgres server\n## Problem\r\nThe current docker image requires the user to already have a Postgres server running on their machine. This is a hassle for someone looking to try out Matheasar quickly.\r\n\r\n## Proposed solution\r\nProvide a docker image containing a Postgres server along with the Mathesar server\r\n\r\n\r\n\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    \"mathesar\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"whitenoise.middleware.WhiteNoiseMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\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\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', cast=Csv(pipe_delim))\n}\n\nDATABASES[decouple_config('DJANGO_DATABASE_KEY', default=\"default\")] = decouple_config('DJANGO_DATABASE_URL', cast=db_url, default='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')\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())\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_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 = 'http://localhost:3000'\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", "path": "config/settings/common_settings.py"}, {"content": "from psycopg.errors import InsufficientPrivilege\nfrom sqlalchemy import text\nfrom sqlalchemy.exc import OperationalError, ProgrammingError\n\nfrom db import engine\nfrom db.sql import install as sql_install\nfrom db.types import install as types_install\n\n\ndef install_mathesar(\n        database_name, username, password, hostname, port, skip_confirm\n):\n    \"\"\"Create database and install Mathesar on it.\"\"\"\n    user_db_engine = engine.create_future_engine(\n        username, password, hostname, database_name, port,\n        connect_args={\"connect_timeout\": 10}\n    )\n    try:\n        user_db_engine.connect()\n        print(f\"Installing Mathesar on preexisting PostgreSQL database {database_name} at host {hostname}...\")\n        sql_install.install(user_db_engine)\n        types_install.install_mathesar_on_database(user_db_engine)\n        user_db_engine.dispose()\n    except OperationalError:\n        database_created = _create_database(\n            database_name=database_name,\n            hostname=hostname,\n            username=username,\n            password=password,\n            port=port,\n            skip_confirm=skip_confirm\n        )\n        if database_created:\n            print(f\"Installing Mathesar on PostgreSQL database {database_name} at host {hostname}...\")\n            sql_install.install(user_db_engine)\n            types_install.install_mathesar_on_database(user_db_engine)\n            user_db_engine.dispose()\n        else:\n            print(f\"Skipping installing on DB with key {database_name}.\")\n\n\ndef _create_database(database_name, hostname, username, password, port, skip_confirm=True):\n    if skip_confirm is True:\n        create_database = \"y\"\n    else:\n        create_database = input(\n            f\"Create a new Database called {database_name}? (y/n) > \"\n        )\n    if create_database.lower() in [\"y\", \"yes\"]:\n        # We need to connect to an existing database inorder to create a new Database.\n        # So we use the default Database `postgres` that comes with postgres.\n        # TODO Throw correct error when the default postgres database does not exists(which is very rare but still possible)\n        root_database = \"postgres\"\n        root_db_engine = engine.create_future_engine(\n            username, password, hostname, root_database, port,\n            connect_args={\"connect_timeout\": 10}\n        )\n        try:\n            with root_db_engine.connect() as conn:\n                conn.execution_options(isolation_level=\"AUTOCOMMIT\")\n                conn.execute(text(f'CREATE DATABASE \"{database_name}\"'))\n            root_db_engine.dispose()\n            print(f\"Created DB is {database_name}.\")\n            return True\n        except ProgrammingError as e:\n            if isinstance(e.orig, InsufficientPrivilege):\n                print(f\"Database {database_name} could not be created due to Insufficient Privilege\")\n                return False\n        except Exception:\n            print(f\"Database {database_name} could not be created!\")\n            return False\n    else:\n        print(f\"Database {database_name} not created!\")\n        return False\n", "path": "db/install.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    \"drf_spectacular\",\n    \"mathesar\",\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"whitenoise.middleware.WhiteNoiseMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\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\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', cast=Csv(pipe_delim))\n}\n\nDATABASES[decouple_config('DJANGO_DATABASE_KEY', default=\"default\")] = decouple_config('DJANGO_DATABASE_URL', cast=db_url, default='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_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 = 'http://localhost:3000'\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", "path": "config/settings/common_settings.py"}, {"content": "from psycopg.errors import InsufficientPrivilege\nfrom sqlalchemy import text\nfrom sqlalchemy.exc import OperationalError, ProgrammingError\n\nfrom db import engine\nfrom db.sql import install as sql_install\nfrom db.types import install as types_install\n\n\ndef install_mathesar(\n        database_name, username, password, hostname, port, skip_confirm\n):\n    \"\"\"Create database and install Mathesar on it.\"\"\"\n    user_db_engine = engine.create_future_engine(\n        username, password, hostname, database_name, port,\n        connect_args={\"connect_timeout\": 10}\n    )\n    try:\n        user_db_engine.connect()\n        print(f\"Installing Mathesar on preexisting PostgreSQL database {database_name} at host {hostname}...\")\n        sql_install.install(user_db_engine)\n        types_install.install_mathesar_on_database(user_db_engine)\n        user_db_engine.dispose()\n    except OperationalError:\n        database_created = _create_database(\n            database_name=database_name,\n            hostname=hostname,\n            username=username,\n            password=password,\n            port=port,\n            skip_confirm=skip_confirm\n        )\n        if database_created:\n            print(f\"Installing Mathesar on PostgreSQL database {database_name} at host {hostname}...\")\n            sql_install.install(user_db_engine)\n            types_install.install_mathesar_on_database(user_db_engine)\n            user_db_engine.dispose()\n        else:\n            print(f\"Skipping installing on DB with key {database_name}.\")\n\n\ndef _create_database(database_name, hostname, username, password, port, skip_confirm=True):\n    if skip_confirm is True:\n        create_database = \"y\"\n    else:\n        create_database = input(\n            f\"Create a new Database called {database_name}? (y/n) > \"\n        )\n    if create_database.lower() in [\"y\", \"yes\"]:\n        # We need to connect to an existing database inorder to create a new Database.\n        # So we use the default database `postgres` that comes with postgres.\n        # TODO Throw correct error when the default postgres database does not exists(which is very rare but still possible)\n        root_database = \"postgres\"\n        root_db_engine = engine.create_future_engine(\n            username, password, hostname, root_database, port,\n            connect_args={\"connect_timeout\": 10}\n        )\n        try:\n            with root_db_engine.connect() as conn:\n                conn.execution_options(isolation_level=\"AUTOCOMMIT\")\n                conn.execute(text(f'CREATE DATABASE \"{database_name}\"'))\n            root_db_engine.dispose()\n            print(f\"Created DB is {database_name}.\")\n            return True\n        except ProgrammingError as e:\n            if isinstance(e.orig, InsufficientPrivilege):\n                print(f\"Database {database_name} could not be created due to Insufficient Privilege\")\n                return False\n        except Exception:\n            print(f\"Database {database_name} could not be created!\")\n            return False\n    else:\n        print(f\"Database {database_name} not created!\")\n        return False\n", "path": "db/install.py"}]}