django-microsys 2.1.9__tar.gz → 2.2.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.
- {django_microsys-2.1.9 → django_microsys-2.2.1}/PKG-INFO +1 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/PKG-INFO +1 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/SOURCES.txt +12 -4
- django_microsys-2.2.1/microsys/VERSION +1 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/context_processors.py +29 -2
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/fetcher.py +21 -4
- django_microsys-2.2.1/microsys/fonts.py +72 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/forms.py +157 -36
- django_microsys-2.2.1/microsys/migrations/0005_systemsettings_allow_user_font_override_and_more.py +29 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/models.py +17 -17
- django_microsys-2.2.1/microsys/static/microsys/fonts/cairo-bold.woff2 +0 -0
- django_microsys-2.2.1/microsys/static/microsys/fonts/cairo-medium.woff2 +0 -0
- django_microsys-2.2.1/microsys/static/microsys/fonts/cairo-regular.woff2 +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/language/css/main.css +1 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/main.css +17 -25
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/system_setup.css +55 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/base_head.js +7 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/base_runtime.js +1 -2
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/options.js +21 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/system_setup.js +64 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/base.html +9 -3
- django_microsys-2.2.1/microsys/templates/microsys/includes/font_previews.html +12 -0
- django_microsys-2.2.1/microsys/templates/microsys/includes/font_settings_matrix.html +46 -0
- django_microsys-2.2.1/microsys/templates/microsys/includes/language_fonts_editor.html +36 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/options.html +25 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/tables/table.html +1 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templatetags/microsys_tags.py +11 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/translations.py +47 -15
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/utils.py +78 -8
- django_microsys-2.1.9/microsys/VERSION +0 -1
- {django_microsys-2.1.9 → django_microsys-2.2.1}/LICENSE +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/MANIFEST.in +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/README.md +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/dependency_links.txt +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/entry_points.txt +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/requires.txt +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/django_microsys.egg-info/top_level.txt +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/__main__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/admin.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/api.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/apps.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/cli.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/constants.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/discovery.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/filters.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/formats/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/formats/ar/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/formats/ar/formats.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/formats/en/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/formats/en/formats.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/guards.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/management/commands/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/management/commands/microsys_check.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/management/commands/microsys_setup.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/management/commands/migrator.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/management/commands/seed_activity_log.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/managers.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/middleware.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/migrations/0001_initial.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/migrations/0002_public_registration.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/migrations/0003_public_root_split.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/migrations/0004_client_ip_and_trusted_devices.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/migrations/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/patches.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/registration.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/README.md.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/__init__.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/apps.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/filters.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/forms.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/migrations/__init__.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/models.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/tables.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/templates/example_record_confirm_delete.html.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/templates/example_record_detail.html.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/templates/example_record_form.html.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/templates/example_record_list.html.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/tests/__init__.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/tests/test_app.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/translations.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/urls.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/app/views.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/.nginx/nginx.conf.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/.secrets/.env.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/Dockerfile.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/README.md.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/compose.dev.yml.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/compose.yml.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/dockerignore.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/docs/README.md.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/entrypoint.sh.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/gitattributes.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/gitignore.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/gunicorn.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/manage.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/__init__.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/asgi.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/celery.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/settings.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/urls.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/package/wsgi.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/req.txt.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/start.ps1.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/start.sh.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/tests/__init__.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/tests/test_scaffold.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/scaffold_templates/project/tools/smtp_relay.py.tmpl +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/signals.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap-icons.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap-icons.woff +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap-icons.woff2 +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.bundle.min.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.bundle.min.js.map +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.min.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.min.css.map +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.rtl.min.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/bootstrap/bootstrap.rtl.min.css.map +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/favicon.ico +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/img/base_logo.webp +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/img/default_profile.webp +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/img/login_logo.webp +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/accessibility/css/main.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/accessibility/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/activitylog/js/main.js +0 -0
- {django_microsys-2.1.9/microsys/static/microsys/language → django_microsys-2.2.1/microsys/static/microsys}/fonts/TwemojiCountryFlags.woff2 +0 -0
- /django_microsys-2.1.9/microsys/static/microsys/main/fonts/Shabwa-Bold.woff2 → /django_microsys-2.2.1/microsys/static/microsys/fonts/shabwa-bold.woff2 +0 -0
- /django_microsys-2.1.9/microsys/static/microsys/main/fonts/Shabwa-Medium.woff2 → /django_microsys-2.2.1/microsys/static/microsys/fonts/shabwa-medium.woff2 +0 -0
- /django_microsys-2.1.9/microsys/static/microsys/main/fonts/Shabwa.woff2 → /django_microsys-2.2.1/microsys/static/microsys/fonts/shabwa-regular.woff2 +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/forms/css/file_field.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/forms/css/form_actions.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/forms/css/form_fields.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/forms/js/file_field.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/forms/js/filter_form.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/autofill/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/context_menu/css/main.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/context_menu/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/context_menu/js/section_manager.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/dynamic_modal/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/prevent_double_submit.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/scan_link/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/scan_link/js/scan_button.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/helpers/wizard/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/language/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/language/js/translations.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/buttons.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/dropdowns.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/index_cards.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/options.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/pagination.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/selectors.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/tables.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/template_cleanup.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/css/titlebar.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/selectors.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/main/js/tables.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sections/js/manage_sections.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/css/main.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/css/reorder.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/css/theme_picker.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/js/preload.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/js/reorder.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/sidebar/js/theme_picker.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/blue.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/dark.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/gold.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/gothic.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/green.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/light.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/mono.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/neon.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/red.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/css/retro.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/themes/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/tutorial/css/main.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/tutorial/js/driver.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/tutorial/js/main.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/css/login.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/css/permissions.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/css/profile.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/css/user_hub.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/login.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/manage_users.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/permissions.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/profile_2fa.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/profile_image_widget.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/twofa_verify.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/microsys/users/js/user_hub.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/vanillajs-datepicker/datepicker-bs5.min.css +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/static/vanillajs-datepicker/datepicker.min.js +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/tables.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/bootstrap5/layout/field_file.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/2fa/verify.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/activitylog/activity_log.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/activitylog/activity_log_detail_modal.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/form_base.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/assets_head.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/assets_scripts.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/crispy_file_field.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/file_input.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/filter_assets_head.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/forms/filter_assets_scripts.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/dynamic_modal.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/dynamic_modal_combined.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/dynamic_modal_detail.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/dynamic_modal_form.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/dynamic_modal_list.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/helpers/micro_context_menu.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/language_catalog_editor.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/language_previews.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/sidebar_builder.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/sidebar_density_previews.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/sidebar_items.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/system_names_editor.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/system_setup.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/table_density_previews.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/theme_previews.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/theme_settings_matrix.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/titlebar.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/translation_matrix_editor.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/includes/tutorial.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/list_base.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/registration/pending.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/scopes/scope_actions.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/scopes/scope_form.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/scopes/scope_manager.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sections/manage_sections.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sections/subsection_select.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sidebar/auto.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sidebar/extra_groups.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sidebar/main.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/sidebar/tree.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/grouped_permissions.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/manage_users.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/profile.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/profile_image_widget.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/user_detail_modal.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/microsys/users/user_hub.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/registration/email/verify_registration.txt +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/registration/login.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/registration/register.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/registration/register_sent.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templates/registration/register_verify.html +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templatetags/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templatetags/microsys_translation.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/templatetags/sidebar_tags.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/themes.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/urls.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/__init__.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/activitylog.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/general.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/profile.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/registration.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/scopes.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/sections.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/sidebar.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/twofa.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/views/users.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/microsys/widgets.py +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/pyproject.toml +0 -0
- {django_microsys-2.1.9 → django_microsys-2.2.1}/setup.cfg +0 -0
|
@@ -20,6 +20,7 @@ microsys/context_processors.py
|
|
|
20
20
|
microsys/discovery.py
|
|
21
21
|
microsys/fetcher.py
|
|
22
22
|
microsys/filters.py
|
|
23
|
+
microsys/fonts.py
|
|
23
24
|
microsys/forms.py
|
|
24
25
|
microsys/guards.py
|
|
25
26
|
microsys/managers.py
|
|
@@ -49,6 +50,7 @@ microsys/migrations/0001_initial.py
|
|
|
49
50
|
microsys/migrations/0002_public_registration.py
|
|
50
51
|
microsys/migrations/0003_public_root_split.py
|
|
51
52
|
microsys/migrations/0004_client_ip_and_trusted_devices.py
|
|
53
|
+
microsys/migrations/0005_systemsettings_allow_user_font_override_and_more.py
|
|
52
54
|
microsys/migrations/__init__.py
|
|
53
55
|
microsys/scaffold_templates/app/README.md.tmpl
|
|
54
56
|
microsys/scaffold_templates/app/__init__.py.tmpl
|
|
@@ -108,6 +110,13 @@ microsys/static/img/login_logo.webp
|
|
|
108
110
|
microsys/static/microsys/accessibility/css/main.css
|
|
109
111
|
microsys/static/microsys/accessibility/js/main.js
|
|
110
112
|
microsys/static/microsys/activitylog/js/main.js
|
|
113
|
+
microsys/static/microsys/fonts/TwemojiCountryFlags.woff2
|
|
114
|
+
microsys/static/microsys/fonts/cairo-bold.woff2
|
|
115
|
+
microsys/static/microsys/fonts/cairo-medium.woff2
|
|
116
|
+
microsys/static/microsys/fonts/cairo-regular.woff2
|
|
117
|
+
microsys/static/microsys/fonts/shabwa-bold.woff2
|
|
118
|
+
microsys/static/microsys/fonts/shabwa-medium.woff2
|
|
119
|
+
microsys/static/microsys/fonts/shabwa-regular.woff2
|
|
111
120
|
microsys/static/microsys/forms/css/file_field.css
|
|
112
121
|
microsys/static/microsys/forms/css/form_actions.css
|
|
113
122
|
microsys/static/microsys/forms/css/form_fields.css
|
|
@@ -123,7 +132,6 @@ microsys/static/microsys/helpers/scan_link/js/main.js
|
|
|
123
132
|
microsys/static/microsys/helpers/scan_link/js/scan_button.js
|
|
124
133
|
microsys/static/microsys/helpers/wizard/js/main.js
|
|
125
134
|
microsys/static/microsys/language/css/main.css
|
|
126
|
-
microsys/static/microsys/language/fonts/TwemojiCountryFlags.woff2
|
|
127
135
|
microsys/static/microsys/language/js/main.js
|
|
128
136
|
microsys/static/microsys/language/js/translations.js
|
|
129
137
|
microsys/static/microsys/main/css/buttons.css
|
|
@@ -137,9 +145,6 @@ microsys/static/microsys/main/css/system_setup.css
|
|
|
137
145
|
microsys/static/microsys/main/css/tables.css
|
|
138
146
|
microsys/static/microsys/main/css/template_cleanup.css
|
|
139
147
|
microsys/static/microsys/main/css/titlebar.css
|
|
140
|
-
microsys/static/microsys/main/fonts/Shabwa-Bold.woff2
|
|
141
|
-
microsys/static/microsys/main/fonts/Shabwa-Medium.woff2
|
|
142
|
-
microsys/static/microsys/main/fonts/Shabwa.woff2
|
|
143
148
|
microsys/static/microsys/main/js/base_head.js
|
|
144
149
|
microsys/static/microsys/main/js/base_runtime.js
|
|
145
150
|
microsys/static/microsys/main/js/options.js
|
|
@@ -200,7 +205,10 @@ microsys/templates/microsys/helpers/dynamic_modal_detail.html
|
|
|
200
205
|
microsys/templates/microsys/helpers/dynamic_modal_form.html
|
|
201
206
|
microsys/templates/microsys/helpers/dynamic_modal_list.html
|
|
202
207
|
microsys/templates/microsys/helpers/micro_context_menu.html
|
|
208
|
+
microsys/templates/microsys/includes/font_previews.html
|
|
209
|
+
microsys/templates/microsys/includes/font_settings_matrix.html
|
|
203
210
|
microsys/templates/microsys/includes/language_catalog_editor.html
|
|
211
|
+
microsys/templates/microsys/includes/language_fonts_editor.html
|
|
204
212
|
microsys/templates/microsys/includes/language_previews.html
|
|
205
213
|
microsys/templates/microsys/includes/options.html
|
|
206
214
|
microsys/templates/microsys/includes/sidebar_builder.html
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.2.1
|
|
@@ -177,7 +177,7 @@ def microsys_context(request):
|
|
|
177
177
|
context = {}
|
|
178
178
|
|
|
179
179
|
# 1. Branding / App Config
|
|
180
|
-
from .utils import build_config_groups, get_system_config
|
|
180
|
+
from .utils import build_config_groups, get_system_config, normalize_allowed_fonts
|
|
181
181
|
final_config = get_system_config()
|
|
182
182
|
|
|
183
183
|
# 4. Language / i18n (resolved BEFORE branding overrides so we know current_lang)
|
|
@@ -342,7 +342,34 @@ def microsys_context(request):
|
|
|
342
342
|
final_config,
|
|
343
343
|
context['titlebar'],
|
|
344
344
|
)
|
|
345
|
-
|
|
345
|
+
# 8. Font Resolution
|
|
346
|
+
from .fonts import generate_font_face_css, get_builtin_fonts
|
|
347
|
+
allowed_fonts = normalize_allowed_fonts(final_config.get('allowed_fonts'))
|
|
348
|
+
context['font_face_css'] = generate_font_face_css(allowed_fonts)
|
|
349
|
+
|
|
350
|
+
allow_user_font_override = bool(final_config.get('allow_user_font_override', True))
|
|
351
|
+
default_fonts_by_lang = final_config.get('default_fonts', {})
|
|
352
|
+
|
|
353
|
+
active_font = None
|
|
354
|
+
if allow_user_font_override:
|
|
355
|
+
active_font = user_prefs.get('font')
|
|
356
|
+
|
|
357
|
+
if not active_font or active_font not in allowed_fonts:
|
|
358
|
+
active_font = default_fonts_by_lang.get(current_lang)
|
|
359
|
+
|
|
360
|
+
if not active_font or active_font not in allowed_fonts:
|
|
361
|
+
# Global fallback based on current language
|
|
362
|
+
active_font = 'shabwa' if current_lang == 'ar' else 'cairo'
|
|
363
|
+
|
|
364
|
+
# Ensure active_font is valid, else hard fallback to shabwa
|
|
365
|
+
if active_font not in allowed_fonts and allowed_fonts:
|
|
366
|
+
active_font = allowed_fonts[0]
|
|
367
|
+
elif not active_font:
|
|
368
|
+
active_font = 'shabwa'
|
|
369
|
+
|
|
370
|
+
context['active_font'] = active_font
|
|
371
|
+
context['font_picker_enabled'] = bool(allow_user_font_override and len(allowed_fonts) > 1)
|
|
372
|
+
|
|
346
373
|
return context
|
|
347
374
|
|
|
348
375
|
def clear_sidebar_cache():
|
|
@@ -4,12 +4,29 @@ from django.http import HttpResponse, HttpResponseRedirect
|
|
|
4
4
|
from django.db.models.query import QuerySet
|
|
5
5
|
from django.contrib import messages
|
|
6
6
|
from django.db.models import FileField
|
|
7
|
+
from django.utils.http import url_has_allowed_host_and_scheme
|
|
7
8
|
from io import BytesIO
|
|
8
9
|
import mimetypes
|
|
9
10
|
import openpyxl
|
|
10
11
|
import zipfile
|
|
11
12
|
from .utils import log_user_action
|
|
12
13
|
|
|
14
|
+
def _safe_referer(request, fallback='/'):
|
|
15
|
+
referer = request.META.get('HTTP_REFERER')
|
|
16
|
+
if referer:
|
|
17
|
+
from django.conf import settings
|
|
18
|
+
allowed_hosts = {request.get_host()}
|
|
19
|
+
if hasattr(settings, 'ALLOWED_HOSTS') and settings.ALLOWED_HOSTS:
|
|
20
|
+
for host in settings.ALLOWED_HOSTS:
|
|
21
|
+
if host:
|
|
22
|
+
if host.startswith('.'):
|
|
23
|
+
allowed_hosts.add(host[1:])
|
|
24
|
+
elif host != '*':
|
|
25
|
+
allowed_hosts.add(host)
|
|
26
|
+
if url_has_allowed_host_and_scheme(url=referer, allowed_hosts=allowed_hosts, require_https=request.is_secure()):
|
|
27
|
+
return referer
|
|
28
|
+
return fallback
|
|
29
|
+
|
|
13
30
|
# Universal Downloader
|
|
14
31
|
#####################################################################
|
|
15
32
|
def fetch_file(request, data, file_type=None):
|
|
@@ -38,7 +55,7 @@ def fetch_file(request, data, file_type=None):
|
|
|
38
55
|
|
|
39
56
|
if not records:
|
|
40
57
|
messages.error(request, "لا توجد سجلات للتحميل.")
|
|
41
|
-
return HttpResponseRedirect(request
|
|
58
|
+
return HttpResponseRedirect(_safe_referer(request))
|
|
42
59
|
|
|
43
60
|
# 2. Collect Files
|
|
44
61
|
files_to_download = []
|
|
@@ -78,7 +95,7 @@ def fetch_file(request, data, file_type=None):
|
|
|
78
95
|
# 3. Decision: Error, Single File, or Zip
|
|
79
96
|
if not files_to_download:
|
|
80
97
|
messages.error(request, "لا توجد ملفات صالحة للتحميل في السجلات المختارة.")
|
|
81
|
-
return HttpResponseRedirect(request
|
|
98
|
+
return HttpResponseRedirect(_safe_referer(request))
|
|
82
99
|
|
|
83
100
|
if len(files_to_download) == 1:
|
|
84
101
|
# Serve Single File
|
|
@@ -248,7 +265,7 @@ def fetch_excel(request, queryset, exclude_fields=None, hidden_fields=None, shee
|
|
|
248
265
|
"""
|
|
249
266
|
if not queryset:
|
|
250
267
|
messages.error(request, "لا توجد بيانات للتصدير.")
|
|
251
|
-
return HttpResponseRedirect(request
|
|
268
|
+
return HttpResponseRedirect(_safe_referer(request))
|
|
252
269
|
|
|
253
270
|
# Normalize to iterable if list passed
|
|
254
271
|
data_list = queryset
|
|
@@ -260,7 +277,7 @@ def fetch_excel(request, queryset, exclude_fields=None, hidden_fields=None, shee
|
|
|
260
277
|
|
|
261
278
|
if not model:
|
|
262
279
|
messages.error(request, "تعذر تحديد نموذج البيانات.")
|
|
263
|
-
return HttpResponseRedirect(request
|
|
280
|
+
return HttpResponseRedirect(_safe_referer(request))
|
|
264
281
|
|
|
265
282
|
from openpyxl.utils import get_column_letter
|
|
266
283
|
from django.db.models import FileField, DateTimeField
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
from django.conf import settings
|
|
3
|
+
from django.templatetags.static import static
|
|
4
|
+
|
|
5
|
+
# Registry for built-in fonts provided by the package
|
|
6
|
+
_FONT_REGISTRY = (
|
|
7
|
+
{
|
|
8
|
+
'slug': 'shabwa',
|
|
9
|
+
'family': 'Shabwa',
|
|
10
|
+
'label': 'Shabwa',
|
|
11
|
+
'variants': [
|
|
12
|
+
{'weight': 400, 'path': 'microsys/fonts/shabwa-regular.woff2'},
|
|
13
|
+
{'weight': 600, 'path': 'microsys/fonts/shabwa-medium.woff2'},
|
|
14
|
+
{'weight': 800, 'path': 'microsys/fonts/shabwa-bold.woff2'},
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
'slug': 'cairo',
|
|
19
|
+
'family': 'Cairo',
|
|
20
|
+
'label': 'Cairo',
|
|
21
|
+
'variants': [
|
|
22
|
+
{'weight': 400, 'path': 'microsys/fonts/cairo-regular.woff2'},
|
|
23
|
+
{'weight': 600, 'path': 'microsys/fonts/cairo-medium.woff2'},
|
|
24
|
+
{'weight': 800, 'path': 'microsys/fonts/cairo-bold.woff2'},
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@lru_cache(maxsize=1)
|
|
30
|
+
def get_builtin_fonts():
|
|
31
|
+
"""Returns the list of hardcoded fonts available in the package."""
|
|
32
|
+
return _FONT_REGISTRY
|
|
33
|
+
|
|
34
|
+
def get_font_choices():
|
|
35
|
+
"""Returns a tuple of (slug, label) for form fields."""
|
|
36
|
+
return tuple((f['slug'], f['label']) for f in _FONT_REGISTRY)
|
|
37
|
+
|
|
38
|
+
def get_font_by_slug(slug):
|
|
39
|
+
"""Returns the font configuration dict for a given slug."""
|
|
40
|
+
for font in _FONT_REGISTRY:
|
|
41
|
+
if font['slug'] == slug:
|
|
42
|
+
return font
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
def generate_font_face_css(allowed_fonts=None):
|
|
46
|
+
"""
|
|
47
|
+
Generates the @font-face CSS block for all allowed fonts.
|
|
48
|
+
This can be injected into the base template.
|
|
49
|
+
"""
|
|
50
|
+
fonts_to_load = []
|
|
51
|
+
if allowed_fonts:
|
|
52
|
+
for slug in allowed_fonts:
|
|
53
|
+
font = get_font_by_slug(slug)
|
|
54
|
+
if font:
|
|
55
|
+
fonts_to_load.append(font)
|
|
56
|
+
else:
|
|
57
|
+
fonts_to_load = _FONT_REGISTRY
|
|
58
|
+
|
|
59
|
+
css_lines = []
|
|
60
|
+
for font in fonts_to_load:
|
|
61
|
+
for variant in font['variants']:
|
|
62
|
+
# We use static() to resolve the path correctly
|
|
63
|
+
url = static(variant['path'])
|
|
64
|
+
css_lines.append(f"@font-face {{")
|
|
65
|
+
css_lines.append(f" font-family: '{font['family']}';")
|
|
66
|
+
css_lines.append(f" font-weight: {variant['weight']};")
|
|
67
|
+
css_lines.append(f" font-style: normal;")
|
|
68
|
+
css_lines.append(f" src: url('{url}') format('woff2');")
|
|
69
|
+
css_lines.append(f" font-display: swap;")
|
|
70
|
+
css_lines.append(f"}}")
|
|
71
|
+
|
|
72
|
+
return "\n".join(css_lines)
|
|
@@ -73,12 +73,15 @@ from .utils import (
|
|
|
73
73
|
normalize_sidebar_behavior,
|
|
74
74
|
normalize_system_names,
|
|
75
75
|
normalize_titlebar_config,
|
|
76
|
+
normalize_allowed_fonts,
|
|
76
77
|
)
|
|
77
78
|
from .widgets import MicrosysChoiceSelectorWidget
|
|
78
79
|
|
|
79
80
|
User = get_user_model()
|
|
80
81
|
|
|
81
82
|
THEME_CHOICES = get_theme_choices()
|
|
83
|
+
from .fonts import get_font_choices
|
|
84
|
+
FONT_CHOICES = get_font_choices()
|
|
82
85
|
PERMISSION_UI_EXCLUDED_APP_LABELS = [
|
|
83
86
|
'admin',
|
|
84
87
|
'contenttypes',
|
|
@@ -1456,6 +1459,18 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
1456
1459
|
required=False,
|
|
1457
1460
|
initial=True,
|
|
1458
1461
|
)
|
|
1462
|
+
allowed_fonts = forms.MultipleChoiceField(
|
|
1463
|
+
required=False,
|
|
1464
|
+
choices=FONT_CHOICES,
|
|
1465
|
+
)
|
|
1466
|
+
allow_user_font_override = forms.BooleanField(
|
|
1467
|
+
required=False,
|
|
1468
|
+
initial=True,
|
|
1469
|
+
)
|
|
1470
|
+
default_fonts = forms.CharField(
|
|
1471
|
+
widget=forms.HiddenInput(),
|
|
1472
|
+
required=False,
|
|
1473
|
+
)
|
|
1459
1474
|
default_table_density = forms.ChoiceField(
|
|
1460
1475
|
required=True,
|
|
1461
1476
|
choices=TABLE_DENSITY_CHOICES,
|
|
@@ -1629,6 +1644,9 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
1629
1644
|
'default_theme',
|
|
1630
1645
|
'allowed_themes',
|
|
1631
1646
|
'allow_user_theme_override',
|
|
1647
|
+
'allowed_fonts',
|
|
1648
|
+
'allow_user_font_override',
|
|
1649
|
+
'default_fonts',
|
|
1632
1650
|
'allow_user_language_override',
|
|
1633
1651
|
'default_table_density',
|
|
1634
1652
|
'email_2fa',
|
|
@@ -1665,7 +1683,7 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
1665
1683
|
parsed_step = int(raw_step)
|
|
1666
1684
|
except (TypeError, ValueError):
|
|
1667
1685
|
parsed_step = None
|
|
1668
|
-
if parsed_step in (0, 1, 2, 3, 4):
|
|
1686
|
+
if parsed_step in (0, 1, 2, 3, 4, 5):
|
|
1669
1687
|
self.single_step_mode = True
|
|
1670
1688
|
self.single_step_index = parsed_step
|
|
1671
1689
|
|
|
@@ -1753,11 +1771,27 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
1753
1771
|
'help_sys_allow_user_language_override',
|
|
1754
1772
|
'Allow users to change their display language from Options. When disabled, the system default language is enforced.',
|
|
1755
1773
|
)
|
|
1774
|
+
self.fields['allowed_fonts'].label = s.get('form_sys_allowed_fonts', 'Allowed fonts')
|
|
1775
|
+
self.fields['allowed_fonts'].help_text = s.get(
|
|
1776
|
+
'help_sys_allowed_fonts',
|
|
1777
|
+
'Choose which fonts are available in this project. The default fonts for each language must remain enabled.',
|
|
1778
|
+
)
|
|
1779
|
+
self.fields['allow_user_font_override'].label = s.get('form_sys_allow_user_font_override', 'Allow user font override')
|
|
1780
|
+
self.fields['allow_user_font_override'].help_text = s.get(
|
|
1781
|
+
'help_sys_allow_user_font_override',
|
|
1782
|
+
'Allow users to switch between the allowed fonts at runtime from Options.',
|
|
1783
|
+
)
|
|
1784
|
+
self.fields['default_fonts'].label = s.get('form_sys_default_fonts', 'Default fonts by language')
|
|
1756
1785
|
self.fields['default_table_density'].label = s.get('form_sys_default_table_density', "Default Table Density")
|
|
1757
1786
|
self.fields['default_table_density'].help_text = s.get(
|
|
1758
1787
|
'help_sys_default_table_density',
|
|
1759
1788
|
'Choose the default table density for new users; each user can still override it later from Options.',
|
|
1760
1789
|
)
|
|
1790
|
+
self.fields['default_table_density'].choices = (
|
|
1791
|
+
('dense', s.get('table_density_dense', 'Dense')),
|
|
1792
|
+
(DEFAULT_TABLE_DENSITY, s.get('table_density_balanced', 'Balanced')),
|
|
1793
|
+
('roomy', s.get('table_density_roomy', 'Roomy')),
|
|
1794
|
+
)
|
|
1761
1795
|
self.fields['logo'].label = s.get('form_sys_logo', "System Logo (Logo)")
|
|
1762
1796
|
self.fields['favicon'].label = s.get('form_sys_favicon', "Site Icon (Favicon)")
|
|
1763
1797
|
self.fields['logo'].widget = _build_archive_file_widget(
|
|
@@ -2136,6 +2170,23 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2136
2170
|
if (not getattr(self.instance, 'pk', None) and not getattr(self.instance, 'is_configured', False))
|
|
2137
2171
|
else getattr(self.instance, 'allow_user_theme_override', config.get('allow_user_theme_override', True))
|
|
2138
2172
|
)
|
|
2173
|
+
self.initial['allow_user_font_override'] = bool(
|
|
2174
|
+
config.get('allow_user_font_override', True)
|
|
2175
|
+
if (not getattr(self.instance, 'pk', None) and not getattr(self.instance, 'is_configured', False))
|
|
2176
|
+
else getattr(self.instance, 'allow_user_font_override', config.get('allow_user_font_override', True))
|
|
2177
|
+
)
|
|
2178
|
+
initial_allowed_fonts = normalize_allowed_fonts(
|
|
2179
|
+
(
|
|
2180
|
+
config.get('allowed_fonts')
|
|
2181
|
+
if (not getattr(self.instance, 'pk', None) and not getattr(self.instance, 'is_configured', False))
|
|
2182
|
+
else getattr(self.instance, 'allowed_fonts', None)
|
|
2183
|
+
) or config.get('allowed_fonts')
|
|
2184
|
+
)
|
|
2185
|
+
self.initial['allowed_fonts'] = list(initial_allowed_fonts)
|
|
2186
|
+
instance_default_fonts = getattr(self.instance, 'default_fonts', {}) or {}
|
|
2187
|
+
if not instance_default_fonts:
|
|
2188
|
+
instance_default_fonts = config.get('default_fonts', {})
|
|
2189
|
+
self.initial['default_fonts'] = _json_dump(instance_default_fonts, ensure_ascii=False)
|
|
2139
2190
|
self.initial['allow_user_language_override'] = bool(
|
|
2140
2191
|
config.get('allow_user_language_override', True)
|
|
2141
2192
|
if (not getattr(self.instance, 'pk', None) and not getattr(self.instance, 'is_configured', False))
|
|
@@ -2267,12 +2318,12 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2267
2318
|
sidebar_config['home_url_name'] = None
|
|
2268
2319
|
self.initial['sidebar_config'] = _json_dump(sidebar_config, ensure_ascii=False)
|
|
2269
2320
|
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2321
|
+
initial_sidebar_config = self.initial.get('sidebar_config') or {}
|
|
2322
|
+
if isinstance(initial_sidebar_config, str):
|
|
2323
|
+
try:
|
|
2324
|
+
initial_sidebar_config = json.loads(initial_sidebar_config)
|
|
2325
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
2326
|
+
initial_sidebar_config = {}
|
|
2276
2327
|
|
|
2277
2328
|
self.initial['sidebar_enabled'] = bool(initial_sidebar_config.get('enabled', True))
|
|
2278
2329
|
self.initial['sidebar_enable_reorder'] = bool(initial_sidebar_config.get('enable_reorder', True))
|
|
@@ -2329,26 +2380,32 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2329
2380
|
self.fields['public_root_url_discovered'].widget.option_meta = home_url_option_meta
|
|
2330
2381
|
self.initial['public_root_url_discovered'] = current_public_root_url if current_public_root_url in seen_home_urls else ''
|
|
2331
2382
|
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2383
|
+
initial_languages = self.initial.get('languages') or {}
|
|
2384
|
+
if isinstance(initial_languages, str):
|
|
2385
|
+
try:
|
|
2386
|
+
initial_languages = json.loads(initial_languages)
|
|
2387
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
2388
|
+
initial_languages = {}
|
|
2336
2389
|
current_languages = normalize_language_catalog(initial_languages)
|
|
2337
2390
|
self.initial['languages'] = _json_dump(current_languages, ensure_ascii=False)
|
|
2338
2391
|
if self.initial.get('default_language') not in current_languages:
|
|
2339
2392
|
self.initial['default_language'] = 'en' if 'en' in current_languages else next(iter(current_languages), 'en')
|
|
2340
2393
|
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2394
|
+
initial_system_names = self.initial.get('system_names') or {}
|
|
2395
|
+
if isinstance(initial_system_names, str):
|
|
2396
|
+
try:
|
|
2397
|
+
initial_system_names = json.loads(initial_system_names)
|
|
2398
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
2399
|
+
initial_system_names = {}
|
|
2345
2400
|
initial_system_names = normalize_system_names(initial_system_names)
|
|
2346
2401
|
self.initial['system_names'] = _json_dump(initial_system_names, ensure_ascii=False)
|
|
2347
2402
|
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2403
|
+
initial_translation_overrides = self.initial.get('translations_override') or {}
|
|
2404
|
+
if isinstance(initial_translation_overrides, str):
|
|
2405
|
+
try:
|
|
2406
|
+
initial_translation_overrides = json.loads(initial_translation_overrides)
|
|
2407
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
2408
|
+
initial_translation_overrides = {}
|
|
2352
2409
|
if not isinstance(initial_translation_overrides, dict):
|
|
2353
2410
|
initial_translation_overrides = {}
|
|
2354
2411
|
suggested_languages = [
|
|
@@ -2410,13 +2467,45 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2410
2467
|
'picker_mode': 'setup',
|
|
2411
2468
|
'input_id': 'id_default_theme',
|
|
2412
2469
|
'allowed_input_name': 'allowed_themes',
|
|
2413
|
-
'allowed_themes': set(self.initial.get('allowed_themes', [])
|
|
2470
|
+
'allowed_themes': set(self.initial.get('allowed_themes') if isinstance(self.initial.get('allowed_themes'), (list, tuple, set)) else []),
|
|
2414
2471
|
'MS_TRANS': s,
|
|
2415
2472
|
'MICROSYS_THEMES': get_theme_options(s),
|
|
2416
2473
|
'label': self.fields['default_theme'].label,
|
|
2417
2474
|
'help_text': self.fields['allowed_themes'].help_text,
|
|
2418
2475
|
},
|
|
2419
2476
|
)
|
|
2477
|
+
|
|
2478
|
+
from .fonts import get_builtin_fonts
|
|
2479
|
+
self.font_picker_html = render_to_string(
|
|
2480
|
+
'microsys/includes/font_settings_matrix.html',
|
|
2481
|
+
{
|
|
2482
|
+
'picker_mode': 'setup',
|
|
2483
|
+
'input_id': 'id_allowed_fonts',
|
|
2484
|
+
'allowed_input_name': 'allowed_fonts',
|
|
2485
|
+
'allowed_fonts': set(self.initial.get('allowed_fonts') if isinstance(self.initial.get('allowed_fonts'), (list, tuple, set)) else []),
|
|
2486
|
+
'MS_TRANS': s,
|
|
2487
|
+
'MICROSYS_FONTS': get_builtin_fonts(),
|
|
2488
|
+
'label': self.fields['allowed_fonts'].label,
|
|
2489
|
+
'help_text': self.fields['allowed_fonts'].help_text,
|
|
2490
|
+
},
|
|
2491
|
+
)
|
|
2492
|
+
|
|
2493
|
+
default_fonts_data = self.initial.get('default_fonts') or {}
|
|
2494
|
+
if isinstance(default_fonts_data, str):
|
|
2495
|
+
try:
|
|
2496
|
+
default_fonts_data = json.loads(default_fonts_data)
|
|
2497
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
2498
|
+
default_fonts_data = {}
|
|
2499
|
+
|
|
2500
|
+
self.language_fonts_editor_html = render_to_string(
|
|
2501
|
+
'microsys/includes/language_fonts_editor.html',
|
|
2502
|
+
{
|
|
2503
|
+
'current_languages': current_languages,
|
|
2504
|
+
'default_fonts': default_fonts_data,
|
|
2505
|
+
'MICROSYS_FONTS': get_builtin_fonts(),
|
|
2506
|
+
'MS_TRANS': s,
|
|
2507
|
+
},
|
|
2508
|
+
)
|
|
2420
2509
|
|
|
2421
2510
|
self.sidebar_builder_html = render_to_string(
|
|
2422
2511
|
'microsys/includes/sidebar_builder.html',
|
|
@@ -2424,7 +2513,7 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2424
2513
|
'sidebar_catalog': self.sidebar_catalog,
|
|
2425
2514
|
'sidebar_catalog_json': _json_dump(self.sidebar_catalog, ensure_ascii=False),
|
|
2426
2515
|
'sidebar_catalog_fallback_json': _json_dump(self.sidebar_catalog_fallback, ensure_ascii=False),
|
|
2427
|
-
'sidebar_config_json': self.initial.get('sidebar_config',
|
|
2516
|
+
'sidebar_config_json': _json_dump(self.initial.get('sidebar_config', {}), ensure_ascii=False),
|
|
2428
2517
|
'mode': self.mode,
|
|
2429
2518
|
'MS_TRANS': s,
|
|
2430
2519
|
},
|
|
@@ -2664,21 +2753,7 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2664
2753
|
css_class=_step_css_class(3),
|
|
2665
2754
|
),
|
|
2666
2755
|
Div(
|
|
2667
|
-
HTML(f"<div class='mb-3'><span class='badge rounded-pill text-bg-primary'>{s.get('system_setup_step5', 'Step 5:
|
|
2668
|
-
Row(
|
|
2669
|
-
Div(
|
|
2670
|
-
HTML(self.theme_picker_html),
|
|
2671
|
-
Field('default_theme'),
|
|
2672
|
-
css_class='mb-3'
|
|
2673
|
-
),
|
|
2674
|
-
),
|
|
2675
|
-
Row(
|
|
2676
|
-
build_settings_toggle_field(self, 'allow_user_theme_override', css_class='col-12')
|
|
2677
|
-
),
|
|
2678
|
-
HTML(f"<h6 class='fw-bold my-3'>{s.get('tables_settings_title', 'Tables Settings')}</h6>"),
|
|
2679
|
-
Row(
|
|
2680
|
-
Div(Field('default_table_density'), css_class='col'),
|
|
2681
|
-
),
|
|
2756
|
+
HTML(f"<div class='mb-3'><span class='badge rounded-pill text-bg-primary'>{s.get('system_setup_step5', 'Step 5: Titlebar')}</span></div>"),
|
|
2682
2757
|
HTML(f"<h6 class='fw-bold my-3'>{s.get('titlebar_settings_title', 'Titlebar Settings')}</h6>"),
|
|
2683
2758
|
Row(
|
|
2684
2759
|
build_settings_toggle_field(self, 'titlebar_show_title', css_class='col-lg-6 col-xl-3'),
|
|
@@ -2700,6 +2775,31 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2700
2775
|
),
|
|
2701
2776
|
css_class=_step_css_class(4),
|
|
2702
2777
|
),
|
|
2778
|
+
Div(
|
|
2779
|
+
HTML(f"<div class='mb-3'><span class='badge rounded-pill text-bg-primary'>{s.get('system_setup_step6', 'Step 6: Appearance')}</span></div>"),
|
|
2780
|
+
Row(
|
|
2781
|
+
Div(
|
|
2782
|
+
HTML(self.theme_picker_html),
|
|
2783
|
+
Field('default_theme'),
|
|
2784
|
+
css_class='mb-3'
|
|
2785
|
+
),
|
|
2786
|
+
),
|
|
2787
|
+
Row(
|
|
2788
|
+
build_settings_toggle_field(self, 'allow_user_theme_override', css_class='col-12')
|
|
2789
|
+
),
|
|
2790
|
+
HTML(f"<h6 class='fw-bold my-3'>{s.get('typography_settings_title', 'Typography Settings')}</h6>"),
|
|
2791
|
+
HTML(self.font_picker_html),
|
|
2792
|
+
# Field('allowed_fonts'),
|
|
2793
|
+
build_settings_toggle_field(self, 'allow_user_font_override', css_class='col-12 mt-2'),
|
|
2794
|
+
HTML(self.language_fonts_editor_html),
|
|
2795
|
+
Field('default_fonts'),
|
|
2796
|
+
HTML(f"<h6 class='fw-bold my-3'>{s.get('tables_settings_title', 'Tables Settings')}</h6>"),
|
|
2797
|
+
Row(
|
|
2798
|
+
Div(Field('default_table_density'), css_class='col'),
|
|
2799
|
+
css_class='mb-3'
|
|
2800
|
+
),
|
|
2801
|
+
css_class=_step_css_class(5),
|
|
2802
|
+
),
|
|
2703
2803
|
FormActions(
|
|
2704
2804
|
HTML(
|
|
2705
2805
|
f"<div class='d-flex flex-wrap justify-content-end align-items-center gap-2 mt-4 ms-setup-wizard-actions' dir='{_get_ui_direction()}'>"
|
|
@@ -2772,6 +2872,24 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
2772
2872
|
def clean_default_language(self):
|
|
2773
2873
|
return str(self.cleaned_data.get('default_language') or 'en').strip().lower().replace('_', '-')
|
|
2774
2874
|
|
|
2875
|
+
def clean_allowed_fonts(self):
|
|
2876
|
+
data = self.cleaned_data.get('allowed_fonts')
|
|
2877
|
+
if not data:
|
|
2878
|
+
return []
|
|
2879
|
+
return list(data)
|
|
2880
|
+
|
|
2881
|
+
def clean_default_fonts(self):
|
|
2882
|
+
data = self.cleaned_data.get('default_fonts')
|
|
2883
|
+
if not data:
|
|
2884
|
+
return {}
|
|
2885
|
+
try:
|
|
2886
|
+
parsed = json.loads(data) if isinstance(data, str) else data
|
|
2887
|
+
if not isinstance(parsed, dict):
|
|
2888
|
+
return {}
|
|
2889
|
+
return parsed
|
|
2890
|
+
except json.JSONDecodeError:
|
|
2891
|
+
return {}
|
|
2892
|
+
|
|
2775
2893
|
def clean_default_theme(self):
|
|
2776
2894
|
value = self.cleaned_data.get('default_theme') or 'light'
|
|
2777
2895
|
if not is_valid_theme(value):
|
|
@@ -3152,6 +3270,9 @@ class SystemSettingsForm(forms.ModelForm):
|
|
|
3152
3270
|
instance.translations_override = self.cleaned_data.get('translations_override', {})
|
|
3153
3271
|
instance.allowed_themes = self.cleaned_data.get('allowed_themes', list(normalize_allowed_themes()))
|
|
3154
3272
|
instance.allow_user_theme_override = bool(self.cleaned_data.get('allow_user_theme_override', True))
|
|
3273
|
+
instance.allowed_fonts = self.cleaned_data.get('allowed_fonts', [])
|
|
3274
|
+
instance.allow_user_font_override = bool(self.cleaned_data.get('allow_user_font_override', True))
|
|
3275
|
+
instance.default_fonts = self.cleaned_data.get('default_fonts', {})
|
|
3155
3276
|
instance.allow_user_language_override = bool(self.cleaned_data.get('allow_user_language_override', True))
|
|
3156
3277
|
instance.client_ip_config = self.cleaned_data.get('client_ip_config', default_client_ip_config())
|
|
3157
3278
|
instance.titlebar_config = self.cleaned_data.get('titlebar_config', default_titlebar_config())
|
django_microsys-2.2.1/microsys/migrations/0005_systemsettings_allow_user_font_override_and_more.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated by Django 6.0.5 on 2026-05-16 09:39
|
|
2
|
+
|
|
3
|
+
import microsys.models
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('microsys', '0004_client_ip_and_trusted_devices'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='systemsettings',
|
|
16
|
+
name='allow_user_font_override',
|
|
17
|
+
field=models.BooleanField(default=True, verbose_name='Allow User Font Override'),
|
|
18
|
+
),
|
|
19
|
+
migrations.AddField(
|
|
20
|
+
model_name='systemsettings',
|
|
21
|
+
name='allowed_fonts',
|
|
22
|
+
field=models.JSONField(blank=True, default=microsys.models.default_allowed_fonts, verbose_name='Allowed Fonts'),
|
|
23
|
+
),
|
|
24
|
+
migrations.AddField(
|
|
25
|
+
model_name='systemsettings',
|
|
26
|
+
name='default_fonts',
|
|
27
|
+
field=models.JSONField(blank=True, default=dict, verbose_name='Default Fonts by Language'),
|
|
28
|
+
),
|
|
29
|
+
]
|