mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-07-10 14:52:42 +02:00
Merge pull request #469 from eitchtee/dev
feat(app): add sanity checks for env variables & refactor: order management lists by name instead of id
This commit is contained in:
@@ -25,7 +25,7 @@ def account_groups_index(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def account_groups_list(request):
|
def account_groups_list(request):
|
||||||
account_groups = AccountGroup.objects.all().order_by("id")
|
account_groups = AccountGroup.objects.all().order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"account_groups/fragments/list.html",
|
"account_groups/fragments/list.html",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def accounts_index(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def accounts_list(request):
|
def accounts_list(request):
|
||||||
accounts = Account.objects.all().order_by("id")
|
accounts = Account.objects.all().order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"accounts/fragments/list.html",
|
"accounts/fragments/list.html",
|
||||||
|
|||||||
@@ -23,3 +23,6 @@ class CommonConfig(AppConfig):
|
|||||||
# Delete the cache for update checks to prevent false-positives when the app is restarted
|
# Delete the cache for update checks to prevent false-positives when the app is restarted
|
||||||
# this will be recreated by the check_for_updates task
|
# this will be recreated by the check_for_updates task
|
||||||
cache.delete("update_check")
|
cache.delete("update_check")
|
||||||
|
|
||||||
|
# Register system checks for required environment variables
|
||||||
|
from apps.common import checks # noqa: F401
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
"""
|
||||||
|
Django System Checks for required environment variables.
|
||||||
|
|
||||||
|
This module validates that required environment variables (those without defaults)
|
||||||
|
are present before the application starts.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.checks import Error, register
|
||||||
|
|
||||||
|
|
||||||
|
# List of environment variables that are required (no default values)
|
||||||
|
# Based on the README.md documentation
|
||||||
|
REQUIRED_ENV_VARS = [
|
||||||
|
("SECRET_KEY", "This is used to provide cryptographic signing."),
|
||||||
|
("SQL_DATABASE", "The name of your postgres database."),
|
||||||
|
]
|
||||||
|
|
||||||
|
# List of environment variables that must be valid integers if set
|
||||||
|
INT_ENV_VARS = [
|
||||||
|
("TASK_WORKERS", "How many workers to have for async tasks."),
|
||||||
|
("SESSION_EXPIRY_TIME", "The age of session cookies, in seconds."),
|
||||||
|
("INTERNAL_PORT", "The port on which the app listens on."),
|
||||||
|
("DJANGO_VITE_DEV_SERVER_PORT", "The port where Vite's dev server is running"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def check_required_env_vars(app_configs, **kwargs):
|
||||||
|
"""
|
||||||
|
Check that all required environment variables are set.
|
||||||
|
|
||||||
|
Returns a list of Error objects for any missing required variables.
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for var_name, description in REQUIRED_ENV_VARS:
|
||||||
|
value = os.getenv(var_name)
|
||||||
|
if not value:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
f"Required environment variable '{var_name}' is not set.",
|
||||||
|
hint=f"{description} Please set this variable in your .env file or environment.",
|
||||||
|
id="wygiwyh.E001",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def check_int_env_vars(app_configs, **kwargs):
|
||||||
|
"""
|
||||||
|
Check that environment variables that should be integers are valid.
|
||||||
|
|
||||||
|
Returns a list of Error objects for any invalid integer variables.
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for var_name, description in INT_ENV_VARS:
|
||||||
|
value = os.getenv(var_name)
|
||||||
|
if value is not None:
|
||||||
|
try:
|
||||||
|
int(value)
|
||||||
|
except ValueError:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
f"Environment variable '{var_name}' must be a valid integer, got '{value}'.",
|
||||||
|
hint=f"{description}",
|
||||||
|
id="wygiwyh.E002",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def check_soft_delete_config(app_configs, **kwargs):
|
||||||
|
"""
|
||||||
|
Check that KEEP_DELETED_TRANSACTIONS_FOR is a valid integer when ENABLE_SOFT_DELETE is enabled.
|
||||||
|
|
||||||
|
Returns a list of Error objects if the configuration is invalid.
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
enable_soft_delete = os.getenv("ENABLE_SOFT_DELETE", "false").lower() == "true"
|
||||||
|
|
||||||
|
if enable_soft_delete:
|
||||||
|
keep_deleted_for = os.getenv("KEEP_DELETED_TRANSACTIONS_FOR")
|
||||||
|
if keep_deleted_for is not None:
|
||||||
|
try:
|
||||||
|
int(keep_deleted_for)
|
||||||
|
except ValueError:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
f"Environment variable 'KEEP_DELETED_TRANSACTIONS_FOR' must be a valid integer when ENABLE_SOFT_DELETE is enabled, got '{keep_deleted_for}'.",
|
||||||
|
hint="Time in days to keep soft deleted transactions for. Set to 0 to keep all transactions indefinitely.",
|
||||||
|
id="wygiwyh.E003",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return errors
|
||||||
@@ -23,7 +23,7 @@ def currencies_index(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def currencies_list(request):
|
def currencies_list(request):
|
||||||
currencies = Currency.objects.all().order_by("id")
|
currencies = Currency.objects.all().order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"currencies/fragments/list.html",
|
"currencies/fragments/list.html",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def strategy_index(request):
|
|||||||
@only_htmx
|
@only_htmx
|
||||||
@login_required
|
@login_required
|
||||||
def strategy_list(request):
|
def strategy_list(request):
|
||||||
strategies = DCAStrategy.objects.all().order_by("created_at")
|
strategies = DCAStrategy.objects.all().order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request, "dca/fragments/strategy/list.html", {"strategies": strategies}
|
request, "dca/fragments/strategy/list.html", {"strategies": strategies}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ is only used for string fields (not dates, decimals, etc.).
|
|||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def categories_list(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def categories_table_active(request):
|
def categories_table_active(request):
|
||||||
categories = TransactionCategory.objects.filter(active=True).order_by("id")
|
categories = TransactionCategory.objects.filter(active=True).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"categories/fragments/table.html",
|
"categories/fragments/table.html",
|
||||||
@@ -47,7 +47,7 @@ def categories_table_active(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def categories_table_archived(request):
|
def categories_table_archived(request):
|
||||||
categories = TransactionCategory.objects.filter(active=False).order_by("id")
|
categories = TransactionCategory.objects.filter(active=False).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"categories/fragments/table.html",
|
"categories/fragments/table.html",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def entities_list(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def entities_table_active(request):
|
def entities_table_active(request):
|
||||||
entities = TransactionEntity.objects.filter(active=True).order_by("id")
|
entities = TransactionEntity.objects.filter(active=True).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"entities/fragments/table.html",
|
"entities/fragments/table.html",
|
||||||
@@ -47,7 +47,7 @@ def entities_table_active(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def entities_table_archived(request):
|
def entities_table_archived(request):
|
||||||
entities = TransactionEntity.objects.filter(active=False).order_by("id")
|
entities = TransactionEntity.objects.filter(active=False).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"entities/fragments/table.html",
|
"entities/fragments/table.html",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def tags_list(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def tags_table_active(request):
|
def tags_table_active(request):
|
||||||
tags = TransactionTag.objects.filter(active=True).order_by("id")
|
tags = TransactionTag.objects.filter(active=True).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"tags/fragments/table.html",
|
"tags/fragments/table.html",
|
||||||
@@ -47,7 +47,7 @@ def tags_table_active(request):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def tags_table_archived(request):
|
def tags_table_archived(request):
|
||||||
tags = TransactionTag.objects.filter(active=False).order_by("id")
|
tags = TransactionTag.objects.filter(active=False).order_by("name")
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"tags/fragments/table.html",
|
"tags/fragments/table.html",
|
||||||
|
|||||||
Reference in New Issue
Block a user