ophix-admin-settings 2026.10.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. ophix_admin_settings-2026.10.4.1/PKG-INFO +72 -0
  2. ophix_admin_settings-2026.10.4.1/README.md +48 -0
  3. ophix_admin_settings-2026.10.4.1/pyproject.toml +53 -0
  4. ophix_admin_settings-2026.10.4.1/setup.cfg +4 -0
  5. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/OPHIX_RELEASE_NOTES.md +37 -0
  6. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/__init__.py +4 -0
  7. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/_version.py +2 -0
  8. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/admin.py +101 -0
  9. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/apps.py +25 -0
  10. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/context_processors.py +3 -0
  11. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/deploy_templates/env.fragment.j2 +2 -0
  12. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/docs/sections.yaml +3 -0
  13. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/docs/server-settings.md +80 -0
  14. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/management/__init__.py +0 -0
  15. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/management/commands/__init__.py +0 -0
  16. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/management/commands/export_settings.py +121 -0
  17. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/management/commands/import_settings.py +160 -0
  18. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0001_initial.py +32 -0
  19. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0002_serversettings_env_colors.py +72 -0
  20. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0003_remove_env_visible_in_favicon.py +16 -0
  21. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0004_serversettings_env_name_remove_help_text.py +25 -0
  22. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0005_serversettings_message_autohide.py +29 -0
  23. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/0006_phase_e_notification_rename.py +30 -0
  24. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/migrations/__init__.py +0 -0
  25. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/models.py +144 -0
  26. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/settings.py +7 -0
  27. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/templates/admin/ophix_admin_settings/serversettings/change_form.html +105 -0
  28. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings/validators.py +82 -0
  29. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/PKG-INFO +72 -0
  30. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/SOURCES.txt +32 -0
  31. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/dependency_links.txt +1 -0
  32. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/entry_points.txt +2 -0
  33. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/requires.txt +2 -0
  34. ophix_admin_settings-2026.10.4.1/src/ophix_admin_settings.egg-info/top_level.txt +1 -0
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: ophix-admin-settings
3
+ Version: 2026.10.4.1
4
+ Summary: Instance settings for Ophix Project Servers - server identity, environment, and language
5
+ Author: Ophix Project
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://ophix.io
8
+ Keywords: django,ophix,admin,settings
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Django
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: django-colorfield
23
+ Requires-Dist: ophix-server-base>=2026.06.08.01
24
+
25
+ # ophix-admin-settings
26
+
27
+ **Know which server you're looking at, every time** — instance identity and environment labelling for every [Ophix](https://ophix.io) server.
28
+
29
+ Running the same admin UI across a dozen servers makes it easy to lose track of which one is actually in front of you — and that's exactly the moment someone edits production thinking it's staging. `ophix-admin-settings` gives every server its own title and a visible environment badge (Production, Staging, Dev, or whatever you call it), right in the header and favicon, so there's never any doubt.
30
+
31
+ This package is automatically included in every Ophix server, no need to separately install it.
32
+
33
+ ---
34
+
35
+ ## What it does
36
+
37
+ Provides a singleton **Server Settings** admin page containing settings that are instance-specific rather than theme-specific. These settings survive theme changes — switching from one theme to another does not alter the server's identity or environment label.
38
+
39
+ | Setting | Description |
40
+ | --- | --- |
41
+ | **Title** | Displayed in the browser tab and admin header (e.g. `TaskServer`, `CredServer`) |
42
+ | **Title visible** | Toggle title display in the admin header |
43
+ | **Environment name** | Short label shown in the header and favicon (e.g. `Production`, `Staging`, `Dev`) |
44
+ | **Env visible in header** | Show or hide the environment badge in the page header |
45
+ | **Env visible in favicon** | Show or hide the environment marker on the favicon |
46
+ | **Language chooser** | Active, control style (default/minimal), and display format (code/name) |
47
+
48
+ ---
49
+
50
+ ## Installation
51
+
52
+ Installed automatically with `ophix-admin-interface`. To install explicitly:
53
+
54
+ ```bash
55
+ pip install ophix-admin-settings
56
+ ```
57
+
58
+ Run migrations after installation:
59
+
60
+ ```bash
61
+ ophix-manage migrate
62
+ ```
63
+
64
+ On first `migrate`, the **title** field is pre-populated from the `SERVER_NAME` setting in `.env` if it is blank.
65
+
66
+ ---
67
+
68
+ ## Docs import
69
+
70
+ ```bash
71
+ ophix-manage update_docs --include-app-docs ophix.core,ophix_admin_settings,ophix_docs
72
+ ```
@@ -0,0 +1,48 @@
1
+ # ophix-admin-settings
2
+
3
+ **Know which server you're looking at, every time** — instance identity and environment labelling for every [Ophix](https://ophix.io) server.
4
+
5
+ Running the same admin UI across a dozen servers makes it easy to lose track of which one is actually in front of you — and that's exactly the moment someone edits production thinking it's staging. `ophix-admin-settings` gives every server its own title and a visible environment badge (Production, Staging, Dev, or whatever you call it), right in the header and favicon, so there's never any doubt.
6
+
7
+ This package is automatically included in every Ophix server, no need to separately install it.
8
+
9
+ ---
10
+
11
+ ## What it does
12
+
13
+ Provides a singleton **Server Settings** admin page containing settings that are instance-specific rather than theme-specific. These settings survive theme changes — switching from one theme to another does not alter the server's identity or environment label.
14
+
15
+ | Setting | Description |
16
+ | --- | --- |
17
+ | **Title** | Displayed in the browser tab and admin header (e.g. `TaskServer`, `CredServer`) |
18
+ | **Title visible** | Toggle title display in the admin header |
19
+ | **Environment name** | Short label shown in the header and favicon (e.g. `Production`, `Staging`, `Dev`) |
20
+ | **Env visible in header** | Show or hide the environment badge in the page header |
21
+ | **Env visible in favicon** | Show or hide the environment marker on the favicon |
22
+ | **Language chooser** | Active, control style (default/minimal), and display format (code/name) |
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ Installed automatically with `ophix-admin-interface`. To install explicitly:
29
+
30
+ ```bash
31
+ pip install ophix-admin-settings
32
+ ```
33
+
34
+ Run migrations after installation:
35
+
36
+ ```bash
37
+ ophix-manage migrate
38
+ ```
39
+
40
+ On first `migrate`, the **title** field is pre-populated from the `SERVER_NAME` setting in `.env` if it is blank.
41
+
42
+ ---
43
+
44
+ ## Docs import
45
+
46
+ ```bash
47
+ ophix-manage update_docs --include-app-docs ophix.core,ophix_admin_settings,ophix_docs
48
+ ```
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ophix-admin-settings"
7
+ version = "2026.10.04.01"
8
+ description = "Instance settings for Ophix Project Servers - server identity, environment, and language"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "Ophix Project" }
14
+ ]
15
+ keywords = ["django", "ophix", "admin", "settings"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Web Environment",
19
+ "Framework :: Django",
20
+ "Intended Audience :: System Administrators",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ ]
29
+ dependencies = [
30
+ "django-colorfield",
31
+ "ophix-server-base>=2026.06.08.01",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://ophix.io"
36
+
37
+ [project.entry-points."ophix.plugins"]
38
+ ophix_admin_settings = "ophix_admin_settings"
39
+
40
+ [tool.setuptools]
41
+ package-dir = { "" = "src" }
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["src"]
45
+
46
+ [tool.setuptools.package-data]
47
+ "ophix_admin_settings" = [
48
+ "OPHIX_RELEASE_NOTES.md",
49
+ "deploy_templates/**/*",
50
+ "docs/**/*",
51
+ "static/**/*",
52
+ "templates/**/*",
53
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,37 @@
1
+ # Ophix Admin Settings Release Notes
2
+
3
+ ## 2026.10.04.01
4
+
5
+ - Reworked `README.md`'s opening with a hook-first pitch (instance identity and environment
6
+ labelling — knowing which server you're looking at before you edit it), as part of the
7
+ 16-package taskserver-release-wave README overhaul.
8
+
9
+ ## 2026.09.26.01
10
+
11
+ - Verified real compatibility under Python 3.14 (not just added the classifier) as part of the taskserver-release-wave compatibility sweep, and added `Programming Language :: Python :: 3.14` to the package classifiers.
12
+
13
+ ## 2026.06.11.01
14
+
15
+ - Added `message_autohide_enabled` and `message_autohide_delay` fields to `ServerSettings`.
16
+ When enabled, success and info message banners are automatically dismissed after the
17
+ configured delay (default 4000 ms). Errors and warnings are never auto-hidden.
18
+ Exposed in the new "Notifications" section of the Server Settings admin page.
19
+
20
+ ## 2026.06.09.02
21
+
22
+ - Added `export_settings` management command — exports the `ServerSettings` singleton
23
+ to a JSON file for backup or server migration.
24
+ - Added `import_settings` management command — imports from an `export_settings` file;
25
+ applies only fields present in the file, reports per-field changes, supports `--dry-run`.
26
+ - Updated server-settings docs: removed stale "Visible in favicon" row, updated env badge
27
+ colour description, added Backup and Migration section.
28
+
29
+ ## 2026.05.31.01
30
+
31
+ - Initial release. Provides the `ServerSettings` singleton model for instance-specific
32
+ configuration: server title, environment label, and language chooser settings.
33
+ - Settings survive theme changes and are independent of the active theme.
34
+ - Title is pre-populated from `SERVER_NAME` in `.env` on first `migrate` if blank.
35
+ - Context processor `ophix_admin_settings.context_processors.settings_context` injects
36
+ `server_settings` into every admin template context via the `CONTEXT_PROCESSORS_APPEND`
37
+ plugin mechanism (requires `ophix-server-base>=2026.05.31.01`).
@@ -0,0 +1,4 @@
1
+ plugin_category = "core"
2
+ plugin_sort = 30
3
+
4
+ default_app_config = "ophix_admin_settings.apps.OphixAdminSettingsConfig"
@@ -0,0 +1,2 @@
1
+ __version__ = "2026.10.04.01"
2
+ __package_name__ = "ophix-admin-settings"
@@ -0,0 +1,101 @@
1
+ from django.conf import settings
2
+ from django.contrib import admin, messages
3
+ from django.http import HttpResponseRedirect
4
+ from django.urls import reverse
5
+ from django.utils.translation import gettext_lazy as _
6
+
7
+ from .models import ServerSettings
8
+
9
+
10
+ @admin.register(ServerSettings)
11
+ class ServerSettingsAdmin(admin.ModelAdmin):
12
+
13
+ def response_change(self, request, obj):
14
+ if "_save" in request.POST:
15
+ self.message_user(request, _("Server Settings saved successfully."), messages.SUCCESS)
16
+ return HttpResponseRedirect(reverse("admin:index"))
17
+ if "_continue" in request.POST:
18
+ self.message_user(request, _("Server Settings saved successfully."), messages.SUCCESS)
19
+ return HttpResponseRedirect(request.path)
20
+ return super().response_change(request, obj)
21
+ fieldsets = (
22
+ (
23
+ _("Server Identity"),
24
+ {
25
+ "classes": ("wide",),
26
+ "fields": ("title", "title_visible"),
27
+ },
28
+ ),
29
+ (
30
+ _("Environment"),
31
+ {
32
+ "classes": ("wide",),
33
+ "fields": (
34
+ "env_name",
35
+ "env_visible_in_header",
36
+ ("env_color", "env_color_dark_use", "env_color_dark"),
37
+ ("env_text_color", "env_text_color_dark_use", "env_text_color_dark"),
38
+ ),
39
+ "description": _(
40
+ "Small badge displayed in the header to identify the deployment environment "
41
+ "(e.g. PROD, DEV, TEST)."
42
+ ),
43
+ },
44
+ ),
45
+ (
46
+ _("Notifications"),
47
+ {
48
+ "classes": ("wide",),
49
+ "fields": ("message_autohide_enabled", "message_autohide_delay"),
50
+ "description": _(
51
+ "Configure automatic dismissal of system notifications. "
52
+ "Only success and info notifications are auto-dismissed; errors and warnings remain until page reload or user dismissal."
53
+ ),
54
+ },
55
+ ),
56
+ (
57
+ _("Language Chooser"),
58
+ {
59
+ "classes": ("wide",),
60
+ "fields": (
61
+ "language_chooser_active",
62
+ "language_chooser_control",
63
+ "language_chooser_display",
64
+ ),
65
+ },
66
+ ),
67
+ )
68
+
69
+ save_on_top = True
70
+
71
+ def change_view(self, request, object_id, form_url="", extra_context=None):
72
+ extra_context = extra_context or {}
73
+ from django.conf import settings as django_settings
74
+ if getattr(django_settings, "SHOW_THEME_MODEL", True):
75
+ try:
76
+ from admin_interface.models import Theme
77
+ extra_context["active_theme"] = Theme.objects.get_active()
78
+ except Exception:
79
+ extra_context["active_theme"] = None
80
+ else:
81
+ extra_context["active_theme"] = None
82
+ return super().change_view(request, object_id, form_url, extra_context)
83
+
84
+ def has_add_permission(self, request):
85
+ return False
86
+
87
+ def has_delete_permission(self, request, obj=None):
88
+ return False
89
+
90
+ def changelist_view(self, request, extra_context=None):
91
+ obj = ServerSettings.load()
92
+ return HttpResponseRedirect(
93
+ reverse("admin:ophix_admin_settings_serversettings_change", args=[obj.pk])
94
+ )
95
+
96
+
97
+ if not getattr(settings, "SHOW_SETTINGS_MODEL", False):
98
+ try:
99
+ admin.site.unregister(ServerSettings)
100
+ except admin.sites.NotRegistered:
101
+ pass
@@ -0,0 +1,25 @@
1
+ from django.apps import AppConfig
2
+ from django.utils.translation import gettext_lazy as _
3
+
4
+
5
+ class OphixAdminSettingsConfig(AppConfig):
6
+ name = "ophix_admin_settings"
7
+ verbose_name = _("Settings")
8
+ admin_order = 810
9
+ default_auto_field = "django.db.models.AutoField"
10
+
11
+ def ready(self):
12
+ from django.db.models.signals import post_migrate
13
+ post_migrate.connect(_init_server_settings, sender=self)
14
+
15
+
16
+ def _init_server_settings(sender, **kwargs):
17
+ from django.apps import apps
18
+ from django.conf import settings
19
+
20
+ ServerSettings = apps.get_model("ophix_admin_settings", "ServerSettings")
21
+ obj = ServerSettings.load()
22
+ if not obj.title:
23
+ server_name = getattr(settings, "SERVER_NAME", "").strip()
24
+ obj.title = ("Ophix " + server_name).strip() if server_name else "Ophix"
25
+ obj.save(update_fields=["title"])
@@ -0,0 +1,3 @@
1
+ def settings_context(request):
2
+ from .models import ServerSettings
3
+ return {"server_settings": ServerSettings.load()}
@@ -0,0 +1,2 @@
1
+ # ophix-admin-settings
2
+ SHOW_SETTINGS_MODEL=True
@@ -0,0 +1,3 @@
1
+ sections:
2
+ - name: Extensions
3
+ collapsed: false
@@ -0,0 +1,80 @@
1
+ ---
2
+ title: Server Settings
3
+ slug: server-settings
4
+ order: 520
5
+ section: Extensions
6
+ ---
7
+
8
+ # Server Settings
9
+
10
+ **Server Settings** holds instance-specific configuration — values that identify this particular server and should survive a theme change. Switching from one theme to another does not alter any setting here.
11
+
12
+ Access it via **Settings** in the admin sidebar.
13
+
14
+ ---
15
+
16
+ ## Server Identity
17
+
18
+ | Setting | Description |
19
+ | --- | --- |
20
+ | **Title** | Displayed first in the browser tab (`TaskServer \| Page Name`) and in the admin header. Pre-populated from `SERVER_NAME` in `.env` on first install if blank. |
21
+ | **Title visible** | Whether the title text appears in the admin header alongside the logo. |
22
+
23
+ ---
24
+
25
+ ## Environment
26
+
27
+ A short label that identifies the deployment environment. Useful when multiple instances of the same domain are running (e.g. production, staging, and dev).
28
+
29
+ | Setting | Description |
30
+ | --- | --- |
31
+ | **Environment name** | The label text, e.g. `Production`, `Staging`, `Dev`. |
32
+ | **Visible in header** | Show or hide the environment badge in the page header. |
33
+ | **Badge color** | Background colour of the environment badge (light and optional dark variant). |
34
+ | **Badge text color** | Text colour of the environment badge (light and optional dark variant). |
35
+
36
+ ---
37
+
38
+ ## Language Chooser
39
+
40
+ Controls whether operators can switch the admin UI language from the page header.
41
+
42
+ | Setting | Description |
43
+ | --- | --- |
44
+ | **Active** | Show or hide the language chooser in the header. |
45
+ | **Control** | Dropdown style: Default Select or Minimal Select. |
46
+ | **Display** | Show language as its two-letter code (e.g. `EN`) or full name (e.g. `English`). |
47
+
48
+ The language chooser only appears when `USE_I18N = True`, at least two languages are configured in `LANGUAGES`, and `LocaleMiddleware` is active.
49
+
50
+ ---
51
+
52
+ ## Backup and Migration
53
+
54
+ `export_settings` and `import_settings` let you preserve and restore the ServerSettings singleton — useful when migrating to a new server or cloning a staging environment.
55
+
56
+ **Export:**
57
+
58
+ ```bash
59
+ ophix-manage export_settings --output-file settings.json
60
+ ```
61
+
62
+ **Preview current values without writing:**
63
+
64
+ ```bash
65
+ ophix-manage export_settings --output-file settings.json --dry-run
66
+ ```
67
+
68
+ **Import (applies all fields from the file):**
69
+
70
+ ```bash
71
+ ophix-manage import_settings --input-file settings.json
72
+ ```
73
+
74
+ **Preview what would change:**
75
+
76
+ ```bash
77
+ ophix-manage import_settings --input-file settings.json --dry-run
78
+ ```
79
+
80
+ Import is safe to re-run — fields that already match the current values are reported as unchanged. Fields present in the file but absent from the model are ignored with a warning; fields absent from the file are left at their current values.
@@ -0,0 +1,121 @@
1
+ """
2
+ ophix-manage export_settings
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Export the ServerSettings singleton to a JSON file for backup or server migration.
5
+
6
+ No passphrase option is provided: ServerSettings contains no sensitive data
7
+ (title, environment badge, language chooser). Protect the file with filesystem
8
+ permissions as you would any configuration file.
9
+
10
+ Examples
11
+ --------
12
+ Export settings:
13
+ ophix-manage export_settings --output-file settings.json
14
+
15
+ Preview (shows current values without writing):
16
+ ophix-manage export_settings --output-file settings.json --dry-run
17
+ """
18
+
19
+ import json
20
+ from pathlib import Path
21
+
22
+ from django.core.management.base import BaseCommand, CommandError
23
+
24
+
25
+ def _build_meta(command: str) -> dict:
26
+ import datetime
27
+ import os
28
+ import socket
29
+
30
+ try:
31
+ import pwd
32
+ run_by = pwd.getpwuid(os.getuid()).pw_name
33
+ except Exception:
34
+ run_by = os.environ.get("USER") or os.environ.get("LOGNAME")
35
+
36
+ from django.conf import settings
37
+ ssh_raw = os.environ.get("SSH_CLIENT", "")
38
+ return {
39
+ "created_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
40
+ "server_name": getattr(settings, "SERVER_NAME", None),
41
+ "server_version": getattr(settings, "SERVER_VERSION", None),
42
+ "hostname": socket.gethostname(),
43
+ "command": command,
44
+ "run_by": run_by,
45
+ "login_user": os.environ.get("SUDO_USER") or None,
46
+ "ssh_origin": ssh_raw.split()[0] if ssh_raw else None,
47
+ }
48
+
49
+
50
+ def _serialize(obj) -> dict:
51
+ return {
52
+ "title": obj.title,
53
+ "title_visible": obj.title_visible,
54
+ "env_name": obj.env_name,
55
+ "env_visible_in_header": obj.env_visible_in_header,
56
+ "env_color": obj.env_color,
57
+ "env_color_dark_use": obj.env_color_dark_use,
58
+ "env_color_dark": obj.env_color_dark,
59
+ "env_text_color": obj.env_text_color,
60
+ "env_text_color_dark_use": obj.env_text_color_dark_use,
61
+ "env_text_color_dark": obj.env_text_color_dark,
62
+ "language_chooser_active": obj.language_chooser_active,
63
+ "language_chooser_control": obj.language_chooser_control,
64
+ "language_chooser_display": obj.language_chooser_display,
65
+ }
66
+
67
+
68
+ class Command(BaseCommand):
69
+ help = "Export the ServerSettings singleton to a JSON file for backup or server migration."
70
+
71
+ def add_arguments(self, parser):
72
+ parser.add_argument(
73
+ "--output-file",
74
+ required=True,
75
+ metavar="FILE",
76
+ help="Destination file path.",
77
+ )
78
+ parser.add_argument(
79
+ "--dry-run",
80
+ action="store_true",
81
+ help="Print the values that would be exported without writing the file.",
82
+ )
83
+ parser.add_argument(
84
+ "--quiet",
85
+ action="store_true",
86
+ help="Suppress all output.",
87
+ )
88
+
89
+ def handle(self, *args, **options):
90
+ from ophix_admin_settings.models import ServerSettings
91
+
92
+ output_path = Path(options["output_file"])
93
+ dry_run = options["dry_run"]
94
+ quiet = options["quiet"]
95
+
96
+ obj = ServerSettings.load()
97
+ data = _serialize(obj)
98
+
99
+ if dry_run:
100
+ if not quiet:
101
+ self.stdout.write("Dry run — current ServerSettings values:")
102
+ for field, value in data.items():
103
+ self.stdout.write(f" {field}: {value!r}")
104
+ return
105
+
106
+ if not output_path.parent.exists():
107
+ raise CommandError(f"Output directory does not exist: {output_path.parent}")
108
+
109
+ payload = {
110
+ "version": 1,
111
+ "meta": _build_meta("export_settings"),
112
+ "settings": data,
113
+ }
114
+
115
+ with output_path.open("w", encoding="utf-8") as f:
116
+ json.dump(payload, f, indent=2)
117
+
118
+ if not quiet:
119
+ self.stdout.write(self.style.SUCCESS(
120
+ f"ServerSettings exported to {output_path}."
121
+ ))