django-microsys 2.1.8__tar.gz → 2.2.0__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 (266) hide show
  1. {django_microsys-2.1.8 → django_microsys-2.2.0}/PKG-INFO +3 -3
  2. {django_microsys-2.1.8 → django_microsys-2.2.0}/README.md +2 -2
  3. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/PKG-INFO +3 -3
  4. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/SOURCES.txt +13 -4
  5. django_microsys-2.2.0/microsys/VERSION +1 -0
  6. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/context_processors.py +31 -2
  7. django_microsys-2.2.0/microsys/fonts.py +72 -0
  8. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/forms.py +392 -43
  9. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/middleware.py +5 -4
  10. django_microsys-2.2.0/microsys/migrations/0004_client_ip_and_trusted_devices.py +40 -0
  11. django_microsys-2.2.0/microsys/migrations/0005_systemsettings_allow_user_font_override_and_more.py +29 -0
  12. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/models.py +48 -17
  13. django_microsys-2.2.0/microsys/static/microsys/fonts/cairo-bold.woff2 +0 -0
  14. django_microsys-2.2.0/microsys/static/microsys/fonts/cairo-medium.woff2 +0 -0
  15. django_microsys-2.2.0/microsys/static/microsys/fonts/cairo-regular.woff2 +0 -0
  16. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/language/css/main.css +1 -1
  17. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/main.css +23 -25
  18. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/tables.css +41 -0
  19. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/base_head.js +7 -0
  20. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/base_runtime.js +1 -2
  21. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/options.js +21 -0
  22. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/system_setup.js +99 -1
  23. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/tutorial/js/main.js +1 -1
  24. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/css/login.css +42 -0
  25. django_microsys-2.2.0/microsys/static/microsys/users/css/permissions.css +285 -0
  26. django_microsys-2.2.0/microsys/static/microsys/users/js/permissions.js +215 -0
  27. django_microsys-2.2.0/microsys/static/microsys/users/js/twofa_verify.js +243 -0
  28. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/tables.py +24 -11
  29. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/2fa/verify.html +64 -18
  30. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/base.html +10 -4
  31. django_microsys-2.2.0/microsys/templates/microsys/includes/font_previews.html +23 -0
  32. django_microsys-2.2.0/microsys/templates/microsys/includes/font_settings_matrix.html +63 -0
  33. django_microsys-2.2.0/microsys/templates/microsys/includes/language_fonts_editor.html +36 -0
  34. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/options.html +25 -1
  35. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/grouped_permissions.html +18 -0
  36. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/profile.html +54 -49
  37. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/user_detail_modal.html +4 -6
  38. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/user_hub.html +1 -7
  39. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templatetags/microsys_tags.py +11 -0
  40. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templatetags/microsys_translation.py +9 -2
  41. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/translations.py +175 -15
  42. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/utils.py +397 -14
  43. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/activitylog.py +10 -4
  44. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/profile.py +49 -2
  45. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/sections.py +0 -5
  46. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/twofa.py +351 -62
  47. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/users.py +40 -3
  48. django_microsys-2.1.8/microsys/VERSION +0 -1
  49. django_microsys-2.1.8/microsys/static/microsys/users/css/permissions.css +0 -105
  50. django_microsys-2.1.8/microsys/static/microsys/users/js/permissions.js +0 -93
  51. django_microsys-2.1.8/microsys/static/microsys/users/js/twofa_verify.js +0 -63
  52. {django_microsys-2.1.8 → django_microsys-2.2.0}/LICENSE +0 -0
  53. {django_microsys-2.1.8 → django_microsys-2.2.0}/MANIFEST.in +0 -0
  54. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/dependency_links.txt +0 -0
  55. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/entry_points.txt +0 -0
  56. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/requires.txt +0 -0
  57. {django_microsys-2.1.8 → django_microsys-2.2.0}/django_microsys.egg-info/top_level.txt +0 -0
  58. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/__init__.py +0 -0
  59. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/__main__.py +0 -0
  60. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/admin.py +0 -0
  61. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/api.py +0 -0
  62. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/apps.py +0 -0
  63. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/cli.py +0 -0
  64. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/constants.py +0 -0
  65. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/discovery.py +0 -0
  66. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/fetcher.py +0 -0
  67. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/filters.py +0 -0
  68. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/formats/__init__.py +0 -0
  69. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/formats/ar/__init__.py +0 -0
  70. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/formats/ar/formats.py +0 -0
  71. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/formats/en/__init__.py +0 -0
  72. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/formats/en/formats.py +0 -0
  73. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/guards.py +0 -0
  74. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/management/commands/__init__.py +0 -0
  75. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/management/commands/microsys_check.py +0 -0
  76. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/management/commands/microsys_setup.py +0 -0
  77. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/management/commands/migrator.py +0 -0
  78. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/management/commands/seed_activity_log.py +0 -0
  79. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/managers.py +0 -0
  80. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/migrations/0001_initial.py +0 -0
  81. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/migrations/0002_public_registration.py +0 -0
  82. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/migrations/0003_public_root_split.py +0 -0
  83. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/migrations/__init__.py +0 -0
  84. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/patches.py +0 -0
  85. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/registration.py +0 -0
  86. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold.py +0 -0
  87. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/README.md.tmpl +0 -0
  88. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/__init__.py.tmpl +0 -0
  89. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/apps.py.tmpl +0 -0
  90. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/filters.py.tmpl +0 -0
  91. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/forms.py.tmpl +0 -0
  92. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/migrations/__init__.py.tmpl +0 -0
  93. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/models.py.tmpl +0 -0
  94. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/tables.py.tmpl +0 -0
  95. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/templates/example_record_confirm_delete.html.tmpl +0 -0
  96. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/templates/example_record_detail.html.tmpl +0 -0
  97. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/templates/example_record_form.html.tmpl +0 -0
  98. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/templates/example_record_list.html.tmpl +0 -0
  99. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/tests/__init__.py.tmpl +0 -0
  100. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/tests/test_app.py.tmpl +0 -0
  101. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/translations.py.tmpl +0 -0
  102. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/urls.py.tmpl +0 -0
  103. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/app/views.py.tmpl +0 -0
  104. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/.nginx/nginx.conf.tmpl +0 -0
  105. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/.secrets/.env.tmpl +0 -0
  106. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/Dockerfile.tmpl +0 -0
  107. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/README.md.tmpl +0 -0
  108. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/compose.dev.yml.tmpl +0 -0
  109. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/compose.yml.tmpl +0 -0
  110. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/dockerignore.tmpl +0 -0
  111. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/docs/README.md.tmpl +0 -0
  112. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/entrypoint.sh.tmpl +0 -0
  113. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/gitattributes.tmpl +0 -0
  114. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/gitignore.tmpl +0 -0
  115. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/gunicorn.py.tmpl +0 -0
  116. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/manage.py.tmpl +0 -0
  117. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/__init__.py.tmpl +0 -0
  118. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/asgi.py.tmpl +0 -0
  119. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/celery.py.tmpl +0 -0
  120. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/settings.py.tmpl +0 -0
  121. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/urls.py.tmpl +0 -0
  122. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/package/wsgi.py.tmpl +0 -0
  123. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/req.txt.tmpl +0 -0
  124. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/start.ps1.tmpl +0 -0
  125. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/start.sh.tmpl +0 -0
  126. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/tests/__init__.py.tmpl +0 -0
  127. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/tests/test_scaffold.py.tmpl +0 -0
  128. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/scaffold_templates/project/tools/smtp_relay.py.tmpl +0 -0
  129. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/signals.py +0 -0
  130. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap-icons.css +0 -0
  131. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap-icons.woff +0 -0
  132. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap-icons.woff2 +0 -0
  133. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.bundle.min.js +0 -0
  134. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.bundle.min.js.map +0 -0
  135. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.min.css +0 -0
  136. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.min.css.map +0 -0
  137. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.rtl.min.css +0 -0
  138. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/bootstrap/bootstrap.rtl.min.css.map +0 -0
  139. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/favicon.ico +0 -0
  140. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/img/base_logo.webp +0 -0
  141. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/img/default_profile.webp +0 -0
  142. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/img/login_logo.webp +0 -0
  143. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/accessibility/css/main.css +0 -0
  144. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/accessibility/js/main.js +0 -0
  145. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/activitylog/js/main.js +0 -0
  146. {django_microsys-2.1.8/microsys/static/microsys/language → django_microsys-2.2.0/microsys/static/microsys}/fonts/TwemojiCountryFlags.woff2 +0 -0
  147. /django_microsys-2.1.8/microsys/static/microsys/main/fonts/Shabwa-Bold.woff2 → /django_microsys-2.2.0/microsys/static/microsys/fonts/shabwa-bold.woff2 +0 -0
  148. /django_microsys-2.1.8/microsys/static/microsys/main/fonts/Shabwa-Medium.woff2 → /django_microsys-2.2.0/microsys/static/microsys/fonts/shabwa-medium.woff2 +0 -0
  149. /django_microsys-2.1.8/microsys/static/microsys/main/fonts/Shabwa.woff2 → /django_microsys-2.2.0/microsys/static/microsys/fonts/shabwa-regular.woff2 +0 -0
  150. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/forms/css/file_field.css +0 -0
  151. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/forms/css/form_actions.css +0 -0
  152. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/forms/css/form_fields.css +0 -0
  153. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/forms/js/file_field.js +0 -0
  154. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/forms/js/filter_form.js +0 -0
  155. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/autofill/js/main.js +0 -0
  156. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/context_menu/css/main.css +0 -0
  157. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/context_menu/js/main.js +0 -0
  158. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/context_menu/js/section_manager.js +0 -0
  159. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/dynamic_modal/js/main.js +0 -0
  160. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/prevent_double_submit.js +0 -0
  161. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/scan_link/js/main.js +0 -0
  162. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/scan_link/js/scan_button.js +0 -0
  163. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/helpers/wizard/js/main.js +0 -0
  164. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/language/js/main.js +0 -0
  165. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/language/js/translations.js +0 -0
  166. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/buttons.css +0 -0
  167. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/dropdowns.css +0 -0
  168. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/index_cards.css +0 -0
  169. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/options.css +0 -0
  170. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/pagination.css +0 -0
  171. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/selectors.css +0 -0
  172. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/system_setup.css +0 -0
  173. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/template_cleanup.css +0 -0
  174. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/css/titlebar.css +0 -0
  175. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/selectors.js +0 -0
  176. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/main/js/tables.js +0 -0
  177. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sections/js/manage_sections.js +0 -0
  178. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/css/main.css +0 -0
  179. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/css/reorder.css +0 -0
  180. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/css/theme_picker.css +0 -0
  181. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/js/main.js +0 -0
  182. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/js/preload.js +0 -0
  183. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/js/reorder.js +0 -0
  184. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/sidebar/js/theme_picker.js +0 -0
  185. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/blue.css +0 -0
  186. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/dark.css +0 -0
  187. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/gold.css +0 -0
  188. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/gothic.css +0 -0
  189. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/green.css +0 -0
  190. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/light.css +0 -0
  191. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/mono.css +0 -0
  192. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/neon.css +0 -0
  193. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/red.css +0 -0
  194. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/css/retro.css +0 -0
  195. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/themes/js/main.js +0 -0
  196. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/tutorial/css/main.css +0 -0
  197. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/tutorial/js/driver.js +0 -0
  198. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/css/profile.css +0 -0
  199. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/css/user_hub.css +0 -0
  200. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/js/login.js +0 -0
  201. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/js/manage_users.js +0 -0
  202. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/js/profile_2fa.js +0 -0
  203. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/js/profile_image_widget.js +0 -0
  204. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/microsys/users/js/user_hub.js +0 -0
  205. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/vanillajs-datepicker/datepicker-bs5.min.css +0 -0
  206. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/static/vanillajs-datepicker/datepicker.min.js +0 -0
  207. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/bootstrap5/layout/field_file.html +0 -0
  208. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/activitylog/activity_log.html +0 -0
  209. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/activitylog/activity_log_detail_modal.html +0 -0
  210. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/form_base.html +0 -0
  211. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/assets_head.html +0 -0
  212. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/assets_scripts.html +0 -0
  213. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/crispy_file_field.html +0 -0
  214. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/file_input.html +0 -0
  215. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/filter_assets_head.html +0 -0
  216. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/forms/filter_assets_scripts.html +0 -0
  217. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/dynamic_modal.html +0 -0
  218. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/dynamic_modal_combined.html +0 -0
  219. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/dynamic_modal_detail.html +0 -0
  220. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/dynamic_modal_form.html +0 -0
  221. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/dynamic_modal_list.html +0 -0
  222. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/helpers/micro_context_menu.html +0 -0
  223. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/language_catalog_editor.html +0 -0
  224. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/language_previews.html +0 -0
  225. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/sidebar_builder.html +0 -0
  226. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/sidebar_density_previews.html +0 -0
  227. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/sidebar_items.html +0 -0
  228. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/system_names_editor.html +0 -0
  229. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/system_setup.html +0 -0
  230. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/table_density_previews.html +0 -0
  231. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/theme_previews.html +0 -0
  232. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/theme_settings_matrix.html +0 -0
  233. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/titlebar.html +0 -0
  234. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/translation_matrix_editor.html +0 -0
  235. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/includes/tutorial.html +0 -0
  236. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/list_base.html +0 -0
  237. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/registration/pending.html +0 -0
  238. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/scopes/scope_actions.html +0 -0
  239. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/scopes/scope_form.html +0 -0
  240. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/scopes/scope_manager.html +0 -0
  241. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sections/manage_sections.html +0 -0
  242. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sections/subsection_select.html +0 -0
  243. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sidebar/auto.html +0 -0
  244. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sidebar/extra_groups.html +0 -0
  245. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sidebar/main.html +0 -0
  246. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/sidebar/tree.html +0 -0
  247. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/tables/table.html +0 -0
  248. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/manage_users.html +0 -0
  249. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/microsys/users/profile_image_widget.html +0 -0
  250. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/registration/email/verify_registration.txt +0 -0
  251. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/registration/login.html +0 -0
  252. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/registration/register.html +0 -0
  253. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/registration/register_sent.html +0 -0
  254. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templates/registration/register_verify.html +0 -0
  255. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templatetags/__init__.py +0 -0
  256. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/templatetags/sidebar_tags.py +0 -0
  257. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/themes.py +0 -0
  258. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/urls.py +0 -0
  259. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/__init__.py +0 -0
  260. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/general.py +0 -0
  261. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/registration.py +0 -0
  262. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/scopes.py +0 -0
  263. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/views/sidebar.py +0 -0
  264. {django_microsys-2.1.8 → django_microsys-2.2.0}/microsys/widgets.py +0 -0
  265. {django_microsys-2.1.8 → django_microsys-2.2.0}/pyproject.toml +0 -0
  266. {django_microsys-2.1.8 → django_microsys-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django_microsys
3
- Version: 2.1.8
3
+ Version: 2.2.0
4
4
  Summary: Django microSYS (System Integration Service) - Multilingual Django Starter Pack, Packed with Features.
5
5
  Author-email: DeBeski <debeski1@gmail.com>
6
6
  License: NON-COMMERCIAL
@@ -137,7 +137,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
137
137
  - Onboarding and runtime configuration:
138
138
  first-launch setup wizard, Options view, runtime System Settings modal, source-tabbed translation overrides, setup import/export, language/theme defaults, and a global Home destination.
139
139
  - User and security operations:
140
- interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows, backup codes, and runtime preference persistence.
140
+ interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows (App, Email, Backup), trusted device tracking for 30 days, and runtime preference persistence.
141
141
  - Generic CRUD infrastructure:
142
142
  dynamic sections, AJAX-driven modal CRUD, automatic form/table/filter discovery, context-menu actions, and reusable event dispatch.
143
143
  - Navigation and UI infrastructure:
@@ -145,7 +145,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
145
145
  - Data movement and productivity helpers:
146
146
  universal file download, Excel export, smart autofill, sticky-form cloning, and generic list/filter helpers.
147
147
  - Audit and governance:
148
- signal-based activity logging, diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
148
+ signal-based activity logging with configurable IP resolution (direct/proxy/header), diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
149
149
  - Optional SSO:
150
150
  `django-microsys-sso` and `django-microsys-sso-client` live as separate optional packages for OIDC provider/client deployments without changing core Microsys runtime behavior.
151
151
  - Framework-level automation:
@@ -103,7 +103,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
103
103
  - Onboarding and runtime configuration:
104
104
  first-launch setup wizard, Options view, runtime System Settings modal, source-tabbed translation overrides, setup import/export, language/theme defaults, and a global Home destination.
105
105
  - User and security operations:
106
- interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows, backup codes, and runtime preference persistence.
106
+ interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows (App, Email, Backup), trusted device tracking for 30 days, and runtime preference persistence.
107
107
  - Generic CRUD infrastructure:
108
108
  dynamic sections, AJAX-driven modal CRUD, automatic form/table/filter discovery, context-menu actions, and reusable event dispatch.
109
109
  - Navigation and UI infrastructure:
@@ -111,7 +111,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
111
111
  - Data movement and productivity helpers:
112
112
  universal file download, Excel export, smart autofill, sticky-form cloning, and generic list/filter helpers.
113
113
  - Audit and governance:
114
- signal-based activity logging, diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
114
+ signal-based activity logging with configurable IP resolution (direct/proxy/header), diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
115
115
  - Optional SSO:
116
116
  `django-microsys-sso` and `django-microsys-sso-client` live as separate optional packages for OIDC provider/client deployments without changing core Microsys runtime behavior.
117
117
  - Framework-level automation:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-microsys
3
- Version: 2.1.8
3
+ Version: 2.2.0
4
4
  Summary: Django microSYS (System Integration Service) - Multilingual Django Starter Pack, Packed with Features.
5
5
  Author-email: DeBeski <debeski1@gmail.com>
6
6
  License: NON-COMMERCIAL
@@ -137,7 +137,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
137
137
  - Onboarding and runtime configuration:
138
138
  first-launch setup wizard, Options view, runtime System Settings modal, source-tabbed translation overrides, setup import/export, language/theme defaults, and a global Home destination.
139
139
  - User and security operations:
140
- interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows, backup codes, and runtime preference persistence.
140
+ interactive user wizard, grouped translated permissions, four-tier staff authorization (superuser, Global Staff, Central Staff, Scoped Staff), permission-based sidebar visibility, profile management, multiple 2FA flows (App, Email, Backup), trusted device tracking for 30 days, and runtime preference persistence.
141
141
  - Generic CRUD infrastructure:
142
142
  dynamic sections, AJAX-driven modal CRUD, automatic form/table/filter discovery, context-menu actions, and reusable event dispatch.
143
143
  - Navigation and UI infrastructure:
@@ -145,7 +145,7 @@ For a fuller setup path, prefix-mount guidance, and first-launch expectations, u
145
145
  - Data movement and productivity helpers:
146
146
  universal file download, Excel export, smart autofill, sticky-form cloning, and generic list/filter helpers.
147
147
  - Audit and governance:
148
- signal-based activity logging, diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
148
+ signal-based activity logging with configurable IP resolution (direct/proxy/header), diff capture, masked sensitive fields, deduplicated entries, download/export logging, and scoped visibility.
149
149
  - Optional SSO:
150
150
  `django-microsys-sso` and `django-microsys-sso-client` live as separate optional packages for OIDC provider/client deployments without changing core Microsys runtime behavior.
151
151
  - Framework-level automation:
@@ -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
@@ -48,6 +49,8 @@ microsys/management/commands/seed_activity_log.py
48
49
  microsys/migrations/0001_initial.py
49
50
  microsys/migrations/0002_public_registration.py
50
51
  microsys/migrations/0003_public_root_split.py
52
+ microsys/migrations/0004_client_ip_and_trusted_devices.py
53
+ microsys/migrations/0005_systemsettings_allow_user_font_override_and_more.py
51
54
  microsys/migrations/__init__.py
52
55
  microsys/scaffold_templates/app/README.md.tmpl
53
56
  microsys/scaffold_templates/app/__init__.py.tmpl
@@ -107,6 +110,13 @@ microsys/static/img/login_logo.webp
107
110
  microsys/static/microsys/accessibility/css/main.css
108
111
  microsys/static/microsys/accessibility/js/main.js
109
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
110
120
  microsys/static/microsys/forms/css/file_field.css
111
121
  microsys/static/microsys/forms/css/form_actions.css
112
122
  microsys/static/microsys/forms/css/form_fields.css
@@ -122,7 +132,6 @@ microsys/static/microsys/helpers/scan_link/js/main.js
122
132
  microsys/static/microsys/helpers/scan_link/js/scan_button.js
123
133
  microsys/static/microsys/helpers/wizard/js/main.js
124
134
  microsys/static/microsys/language/css/main.css
125
- microsys/static/microsys/language/fonts/TwemojiCountryFlags.woff2
126
135
  microsys/static/microsys/language/js/main.js
127
136
  microsys/static/microsys/language/js/translations.js
128
137
  microsys/static/microsys/main/css/buttons.css
@@ -136,9 +145,6 @@ microsys/static/microsys/main/css/system_setup.css
136
145
  microsys/static/microsys/main/css/tables.css
137
146
  microsys/static/microsys/main/css/template_cleanup.css
138
147
  microsys/static/microsys/main/css/titlebar.css
139
- microsys/static/microsys/main/fonts/Shabwa-Bold.woff2
140
- microsys/static/microsys/main/fonts/Shabwa-Medium.woff2
141
- microsys/static/microsys/main/fonts/Shabwa.woff2
142
148
  microsys/static/microsys/main/js/base_head.js
143
149
  microsys/static/microsys/main/js/base_runtime.js
144
150
  microsys/static/microsys/main/js/options.js
@@ -199,7 +205,10 @@ microsys/templates/microsys/helpers/dynamic_modal_detail.html
199
205
  microsys/templates/microsys/helpers/dynamic_modal_form.html
200
206
  microsys/templates/microsys/helpers/dynamic_modal_list.html
201
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
202
210
  microsys/templates/microsys/includes/language_catalog_editor.html
211
+ microsys/templates/microsys/includes/language_fonts_editor.html
203
212
  microsys/templates/microsys/includes/language_previews.html
204
213
  microsys/templates/microsys/includes/options.html
205
214
  microsys/templates/microsys/includes/sidebar_builder.html
@@ -0,0 +1 @@
1
+ 2.2.0
@@ -3,6 +3,7 @@ from urllib.parse import urlsplit
3
3
  from .constants import DEFAULT_TABLE_DENSITY, TABLE_DENSITY_CHOICES, TABLE_DENSITY_VALUES
4
4
  from .utils import (
5
5
  get_effective_allowed_themes,
6
+ get_user_management_tier_state_for_user,
6
7
  has_section_models,
7
8
  is_scope_enabled,
8
9
  normalize_sidebar_behavior,
@@ -176,7 +177,7 @@ def microsys_context(request):
176
177
  context = {}
177
178
 
178
179
  # 1. Branding / App Config
179
- from .utils import build_config_groups, get_system_config
180
+ from .utils import build_config_groups, get_system_config, normalize_allowed_fonts
180
181
  final_config = get_system_config()
181
182
 
182
183
  # 4. Language / i18n (resolved BEFORE branding overrides so we know current_lang)
@@ -232,6 +233,7 @@ def microsys_context(request):
232
233
  context['can_view_user_directory'] = user_can_view_user_directory(request.user)
233
234
  context['can_view_activity_log'] = user_can_view_activity_log(request.user)
234
235
  context['can_view_sections'] = user_has_section_view_permission(request.user)
236
+ context['current_user_management_tier'] = get_user_management_tier_state_for_user(request.user)
235
237
 
236
238
  # 3. User Preferences (for JS injection & server-side logic)
237
239
  user_prefs = {}
@@ -340,7 +342,34 @@ def microsys_context(request):
340
342
  final_config,
341
343
  context['titlebar'],
342
344
  )
343
-
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
+
344
373
  return context
345
374
 
346
375
  def clear_sidebar_cache():
@@ -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)