diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 1896a3e..0cc3f29 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -2,13 +2,12 @@ name: Django CI on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] jobs: build: - runs-on: ubuntu-latest services: @@ -24,20 +23,21 @@ jobs: options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.11 - uses: actions/setup-python@v2 - with: - python-version: 3.11 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Run migrations - run: | - cd backend - python manage.py migrate - - name: Run tests - run: | - cd backend - python manage.py test + - uses: actions/checkout@v2 + - name: Set up Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: 3.11 + - name: Install dependencies + run: | + cd backend + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run migrations + run: | + cd backend + python manage.py migrate + - name: Run tests + run: | + cd backend + python manage.py test diff --git a/.gitignore b/.gitignore index d6a7e2b..a40fc56 100644 --- a/.gitignore +++ b/.gitignore @@ -57,7 +57,6 @@ cover/ # Django stuff: *.log -local_settings.py db.sqlite3 db.sqlite3-journal diff --git a/backend/core/local_settings.py b/backend/core/local_settings.py new file mode 100644 index 0000000..9e7903c --- /dev/null +++ b/backend/core/local_settings.py @@ -0,0 +1,269 @@ +""" +Django settings for core project. + +Generated by 'django-admin startproject' using Django 4.2.6. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from datetime import timedelta +import os +from pathlib import Path +from decouple import config, Csv + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = config('SECRET_KEY', default='j5&66&8@b-!3tbq!=w6-dypl($_0zzoi*ilxd1*&$_6s-59il5') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = config('DEBUG', default=False, cast=bool) + +ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv()) + + +# Application definition + +SITE_ID = 4 + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'allauth.account.auth_backends.AuthenticationBackend', +) + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + + 'tasks', + 'users', + 'authentications', + 'dashboard', + 'boards', + + 'corsheaders', + 'drf_spectacular', + + 'allauth', + 'allauth.account', + 'allauth.socialaccount', + 'allauth.socialaccount.providers.google', + + 'rest_framework', + 'dj_rest_auth', + 'dj_rest_auth.registration', + 'rest_framework.authtoken', +] + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework.authentication.TokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', + ], + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +SPECTACULAR_SETTINGS = { + 'TITLE': 'TurTask API', + 'DESCRIPTION': 'API documentation for TurTask', + 'VERSION': '1.0.0', + 'SERVE_INCLUDE_SCHEMA': False, +} + +REST_USE_JWT = True + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(days=3), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=30), +} + +GOOGLE_CLIENT_ID = config('GOOGLE_CLIENT_ID', default='fake-client-id') +GOOGLE_CLIENT_SECRET = config('GOOGLE_CLIENT_SECRET', default='fake-client-secret') + +SOCIALACCOUNT_PROVIDERS = { + 'google': { + 'APP': { + 'client_id': GOOGLE_CLIENT_ID, + 'secret': GOOGLE_CLIENT_SECRET, + 'key': '' + }, + "SCOPE": [ + "profile", + "email", + ], + "AUTH_PARAMS": { + "access_type": "online", + } + } +} + + +CORS_ALLOW_CREDENTIALS = True +CORS_ALLOW_ALL_ORIGINS = False +CORS_ALLOWED_ORIGINS = [ + "http://localhost:8000", + "http://127.0.0.1:8000", + "http://localhost:5173", +] + +CSRF_TRUSTED_ORIGINS = ["http://localhost:5173"] + +CORS_ORIGIN_WHITELIST = ["*"] + +MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "allauth.account.middleware.AccountMiddleware", +] + +ROOT_URLCONF = 'core.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'templates') + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'core.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': config('DB_NAME', default='github_actions'), + 'USER': config('DB_USER', default='postgres'), + 'PASSWORD': config('DB_PASSWORD', default='postgres'), + 'HOST': config('DB_HOST', default='127.0.0.1'), + 'PORT': config('DB_PORT', default='5432'), + } +} + + +# Cache + +CACHES_LOCATION = f"{config('DB_NAME', default='db_test')}_cache" + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": CACHES_LOCATION, + } +} + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', +] + +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' + +AUTH_USER_MODEL = "users.CustomUser" + +ACCOUNT_EMAIL_REQUIRED = True + +# Storages + +AWS_ACCESS_KEY_ID = config('AMAZON_S3_ACCESS_KEY', default='fake-access-key') +AWS_SECRET_ACCESS_KEY = config('AMAZON_S3_SECRET_ACCESS_KEY', default='fake-secret-access-key') +AWS_STORAGE_BUCKET_NAME = config('BUCKET_NAME', default='fake-bucket-name') +AWS_DEFAULT_ACL = 'public-read' +AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com' +AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'} + +MEDIA_URL = '/mediafiles/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles') + +STORAGES = { + "default": { + "BACKEND": "storages.backends.s3.S3Storage", + "OPTIONS": { + }, + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, +} \ No newline at end of file diff --git a/backend/core/production_settings.py b/backend/core/production_settings.py new file mode 100644 index 0000000..dd9eeb3 --- /dev/null +++ b/backend/core/production_settings.py @@ -0,0 +1,267 @@ +""" +Django settings for core project. + +Generated by 'django-admin startproject' using Django 4.2.6. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from datetime import timedelta +import os +from pathlib import Path +from decouple import config, Csv + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = config('SECRET_KEY', default='j5&66&8@b-!3tbq!=w6-dypl($_0zzoi*ilxd1*&$_6s-59il5') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = config('DEBUG', default=False, cast=bool) + +ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv()) + + +# Application definition + +SITE_ID = 4 + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'allauth.account.auth_backends.AuthenticationBackend', +) + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + + 'tasks', + 'users', + 'authentications', + 'dashboard', + 'boards', + + 'corsheaders', + 'drf_spectacular', + + 'allauth', + 'allauth.account', + 'allauth.socialaccount', + 'allauth.socialaccount.providers.google', + + 'rest_framework', + 'dj_rest_auth', + 'dj_rest_auth.registration', + 'rest_framework.authtoken', +] + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework.authentication.TokenAuthentication', + 'rest_framework_simplejwt.authentication.JWTAuthentication', + 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', + ], + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +SPECTACULAR_SETTINGS = { + 'TITLE': 'TurTask API', + 'DESCRIPTION': 'API documentation for TurTask', + 'VERSION': '1.0.0', + 'SERVE_INCLUDE_SCHEMA': False, +} + +REST_USE_JWT = True + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(days=3), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=30), +} + +GOOGLE_CLIENT_ID = config('GOOGLE_CLIENT_ID', default='fake-client-id') +GOOGLE_CLIENT_SECRET = config('GOOGLE_CLIENT_SECRET', default='fake-client-secret') + +SOCIALACCOUNT_PROVIDERS = { + 'google': { + 'APP': { + 'client_id': GOOGLE_CLIENT_ID, + 'secret': GOOGLE_CLIENT_SECRET, + 'key': '' + }, + "SCOPE": [ + "profile", + "email", + ], + "AUTH_PARAMS": { + "access_type": "online", + } + } +} + + +CORS_ALLOW_CREDENTIALS = True +CORS_ALLOW_ALL_ORIGINS = False +CORS_ALLOWED_ORIGINS = [ + "https://turtask.vercel.app", +] + +CSRF_TRUSTED_ORIGINS = ["https://turtask.vercel.app"] + +CORS_ORIGIN_WHITELIST = ["*"] + +MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "allauth.account.middleware.AccountMiddleware", +] + +ROOT_URLCONF = 'core.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'templates') + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'core.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': config('PGDATABASE', default='github_actions'), + 'USER': config('PGUSER', default='postgres'), + 'PASSWORD': config('PGPASSWORD', default='postgres'), + 'HOST': config('PGHOST', default='127.0.0.1'), + 'PORT': config('PGPORT', default='5432'), + } +} + + +# Cache + +CACHES_LOCATION = "accesstokencache" + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": CACHES_LOCATION, + } +} + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', +] + +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' + +AUTH_USER_MODEL = "users.CustomUser" + +ACCOUNT_EMAIL_REQUIRED = True + +# Storages + +AWS_ACCESS_KEY_ID = config('AMAZON_S3_ACCESS_KEY', default='fake-access-key') +AWS_SECRET_ACCESS_KEY = config('AMAZON_S3_SECRET_ACCESS_KEY', default='fake-secret-access-key') +AWS_STORAGE_BUCKET_NAME = config('BUCKET_NAME', default='fake-bucket-name') +AWS_DEFAULT_ACL = 'public-read' +AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com' +AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'} + +MEDIA_URL = '/mediafiles/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles') + +STORAGES = { + "default": { + "BACKEND": "storages.backends.s3.S3Storage", + "OPTIONS": { + }, + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, +} \ No newline at end of file diff --git a/backend/core/settings.py b/backend/core/settings.py index 9e7903c..7532f01 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -1,269 +1,6 @@ -""" -Django settings for core project. - -Generated by 'django-admin startproject' using Django 4.2.6. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" - -from datetime import timedelta import os -from pathlib import Path -from decouple import config, Csv -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = config('SECRET_KEY', default='j5&66&8@b-!3tbq!=w6-dypl($_0zzoi*ilxd1*&$_6s-59il5') - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = config('DEBUG', default=False, cast=bool) - -ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv()) - - -# Application definition - -SITE_ID = 4 - -AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - 'allauth.account.auth_backends.AuthenticationBackend', -) - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.sites', - - 'tasks', - 'users', - 'authentications', - 'dashboard', - 'boards', - - 'corsheaders', - 'drf_spectacular', - - 'allauth', - 'allauth.account', - 'allauth.socialaccount', - 'allauth.socialaccount.providers.google', - - 'rest_framework', - 'dj_rest_auth', - 'dj_rest_auth.registration', - 'rest_framework.authtoken', -] - -REST_FRAMEWORK = { - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.IsAuthenticated', - - ], - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', - 'rest_framework.authentication.TokenAuthentication', - 'rest_framework_simplejwt.authentication.JWTAuthentication', - 'dj_rest_auth.jwt_auth.JWTCookieAuthentication', - ], - 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', -} - -SPECTACULAR_SETTINGS = { - 'TITLE': 'TurTask API', - 'DESCRIPTION': 'API documentation for TurTask', - 'VERSION': '1.0.0', - 'SERVE_INCLUDE_SCHEMA': False, -} - -REST_USE_JWT = True - -SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(days=3), - 'REFRESH_TOKEN_LIFETIME': timedelta(days=30), -} - -GOOGLE_CLIENT_ID = config('GOOGLE_CLIENT_ID', default='fake-client-id') -GOOGLE_CLIENT_SECRET = config('GOOGLE_CLIENT_SECRET', default='fake-client-secret') - -SOCIALACCOUNT_PROVIDERS = { - 'google': { - 'APP': { - 'client_id': GOOGLE_CLIENT_ID, - 'secret': GOOGLE_CLIENT_SECRET, - 'key': '' - }, - "SCOPE": [ - "profile", - "email", - ], - "AUTH_PARAMS": { - "access_type": "online", - } - } -} - - -CORS_ALLOW_CREDENTIALS = True -CORS_ALLOW_ALL_ORIGINS = False -CORS_ALLOWED_ORIGINS = [ - "http://localhost:8000", - "http://127.0.0.1:8000", - "http://localhost:5173", -] - -CSRF_TRUSTED_ORIGINS = ["http://localhost:5173"] - -CORS_ORIGIN_WHITELIST = ["*"] - -MIDDLEWARE = [ - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - "allauth.account.middleware.AccountMiddleware", -] - -ROOT_URLCONF = 'core.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.join(BASE_DIR, 'templates') - ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'core.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/4.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': config('DB_NAME', default='github_actions'), - 'USER': config('DB_USER', default='postgres'), - 'PASSWORD': config('DB_PASSWORD', default='postgres'), - 'HOST': config('DB_HOST', default='127.0.0.1'), - 'PORT': config('DB_PORT', default='5432'), - } -} - - -# Cache - -CACHES_LOCATION = f"{config('DB_NAME', default='db_test')}_cache" - -CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.db.DatabaseCache", - "LOCATION": CACHES_LOCATION, - } -} - -# Password validation -# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/4.2/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/4.2/howto/static-files/ - -STATIC_URL = 'static/' - -# Default primary key field type -# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - - -SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/userinfo.profile', -] - -LOGIN_REDIRECT_URL = '/' -LOGOUT_REDIRECT_URL = '/' - -AUTH_USER_MODEL = "users.CustomUser" - -ACCOUNT_EMAIL_REQUIRED = True - -# Storages - -AWS_ACCESS_KEY_ID = config('AMAZON_S3_ACCESS_KEY', default='fake-access-key') -AWS_SECRET_ACCESS_KEY = config('AMAZON_S3_SECRET_ACCESS_KEY', default='fake-secret-access-key') -AWS_STORAGE_BUCKET_NAME = config('BUCKET_NAME', default='fake-bucket-name') -AWS_DEFAULT_ACL = 'public-read' -AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com' -AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'} - -MEDIA_URL = '/mediafiles/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles') - -STORAGES = { - "default": { - "BACKEND": "storages.backends.s3.S3Storage", - "OPTIONS": { - }, - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, -} \ No newline at end of file +if os.environ.get("DJANGO_ENV") == "PRODUCTION": + from .production_settings import * +else: + from .local_settings import * \ No newline at end of file diff --git a/backend/core/wsgi.py b/backend/core/wsgi.py index f44964d..a08c895 100644 --- a/backend/core/wsgi.py +++ b/backend/core/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") application = get_wsgi_application() diff --git a/backend/railway.json b/backend/railway.json new file mode 100644 index 0000000..a99f1a8 --- /dev/null +++ b/backend/railway.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://railway.app/railway.schema.json", + "build": { + "builder": "NIXPACKS" + }, + "deploy": { + "startCommand": "python manage.py migrate && python manage.py createcachetable accesstokencache && gunicorn --timeout 500 core.wsgi", + "restartPolicyType": "NEVER", + "restartPolicyMaxRetries": 10 + } +} diff --git a/requirements.txt b/backend/requirements.txt similarity index 87% rename from requirements.txt rename to backend/requirements.txt index 344b980..95962f8 100644 --- a/requirements.txt +++ b/backend/requirements.txt @@ -15,4 +15,6 @@ google-auth-httplib2>=0.1 django-storages[s3]>=1.14 Pillow>=10.1 drf-spectacular>=0.26 -python-dateutil>=2.8 \ No newline at end of file +python-dateutil>=2.8 +gunicorn==21.2.0 +packaging==23.1 \ No newline at end of file