polyadmin 0.1.0b1__py3-none-any.whl

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 (104) hide show
  1. polyadmin/__init__.py +47 -0
  2. polyadmin/core/__init__.py +0 -0
  3. polyadmin/core/_async.py +21 -0
  4. polyadmin/core/action.py +135 -0
  5. polyadmin/core/admin.py +129 -0
  6. polyadmin/core/audit.py +65 -0
  7. polyadmin/core/auth.py +52 -0
  8. polyadmin/core/authorization.py +48 -0
  9. polyadmin/core/csrf.py +70 -0
  10. polyadmin/core/dashboard.py +41 -0
  11. polyadmin/core/delete.py +146 -0
  12. polyadmin/core/exporter.py +136 -0
  13. polyadmin/core/field.py +201 -0
  14. polyadmin/core/filter.py +305 -0
  15. polyadmin/core/inline.py +97 -0
  16. polyadmin/core/login.py +110 -0
  17. polyadmin/core/model_admin.py +349 -0
  18. polyadmin/core/page.py +62 -0
  19. polyadmin/core/pagination.py +70 -0
  20. polyadmin/core/query.py +243 -0
  21. polyadmin/core/relation.py +40 -0
  22. polyadmin/core/slug.py +57 -0
  23. polyadmin/core/template_context.py +679 -0
  24. polyadmin/core/widget.py +280 -0
  25. polyadmin/fastapi/__init__.py +3 -0
  26. polyadmin/fastapi/audit.py +52 -0
  27. polyadmin/fastapi/auth.py +112 -0
  28. polyadmin/fastapi/csrf.py +93 -0
  29. polyadmin/fastapi/deletes.py +76 -0
  30. polyadmin/fastapi/errors.py +93 -0
  31. polyadmin/fastapi/handlers.py +798 -0
  32. polyadmin/fastapi/inlines.py +177 -0
  33. polyadmin/fastapi/locale.py +128 -0
  34. polyadmin/fastapi/login.py +110 -0
  35. polyadmin/fastapi/pages.py +97 -0
  36. polyadmin/fastapi/relations.py +264 -0
  37. polyadmin/fastapi/responses.py +55 -0
  38. polyadmin/fastapi/router.py +174 -0
  39. polyadmin/fastapi/static.py +21 -0
  40. polyadmin/i18n/__init__.py +50 -0
  41. polyadmin/i18n/context.py +54 -0
  42. polyadmin/i18n/negotiation.py +56 -0
  43. polyadmin/i18n/setup.py +81 -0
  44. polyadmin/i18n/translator.py +124 -0
  45. polyadmin/locale/fr/LC_MESSAGES/polyadmin.mo +0 -0
  46. polyadmin/locale/fr/LC_MESSAGES/polyadmin.po +486 -0
  47. polyadmin/locale/polyadmin.pot +485 -0
  48. polyadmin/locale/ru/LC_MESSAGES/polyadmin.mo +0 -0
  49. polyadmin/locale/ru/LC_MESSAGES/polyadmin.po +496 -0
  50. polyadmin/templates/admin/base.html +91 -0
  51. polyadmin/templates/admin/components/action_confirm_modal.html +86 -0
  52. polyadmin/templates/admin/components/csrf-field.html +5 -0
  53. polyadmin/templates/admin/components/error_fragment.html +6 -0
  54. polyadmin/templates/admin/components/field.html +60 -0
  55. polyadmin/templates/admin/components/form_wrapper.html +131 -0
  56. polyadmin/templates/admin/components/icons.html +67 -0
  57. polyadmin/templates/admin/components/inline.html +251 -0
  58. polyadmin/templates/admin/components/inline_fragment.html +2 -0
  59. polyadmin/templates/admin/components/list_content.html +54 -0
  60. polyadmin/templates/admin/components/lookup_results.html +19 -0
  61. polyadmin/templates/admin/components/search.html +19 -0
  62. polyadmin/templates/admin/components/toasts.html +151 -0
  63. polyadmin/templates/admin/components/ui/breadcrumb.html +30 -0
  64. polyadmin/templates/admin/components/ui/bulk-actions.html +69 -0
  65. polyadmin/templates/admin/components/ui/calendar.html +175 -0
  66. polyadmin/templates/admin/components/ui/combobox.html +82 -0
  67. polyadmin/templates/admin/components/ui/delete-preview.html +37 -0
  68. polyadmin/templates/admin/components/ui/dropdown-menu.html +71 -0
  69. polyadmin/templates/admin/components/ui/field.html +110 -0
  70. polyadmin/templates/admin/components/ui/filter-panel.html +155 -0
  71. polyadmin/templates/admin/components/ui/locale-switcher.html +30 -0
  72. polyadmin/templates/admin/components/ui/multi-select.html +253 -0
  73. polyadmin/templates/admin/components/ui/pagination.html +81 -0
  74. polyadmin/templates/admin/components/ui/radio-group.html +28 -0
  75. polyadmin/templates/admin/components/ui/select.html +165 -0
  76. polyadmin/templates/admin/components/ui/sidebar.html +175 -0
  77. polyadmin/templates/admin/components/ui/slider.html +22 -0
  78. polyadmin/templates/admin/components/ui/switch.html +36 -0
  79. polyadmin/templates/admin/components/ui/table.html +221 -0
  80. polyadmin/templates/admin/components/ui/theme-toggle.html +33 -0
  81. polyadmin/templates/admin/dashboard.html +35 -0
  82. polyadmin/templates/admin/error.html +33 -0
  83. polyadmin/templates/admin/login.html +94 -0
  84. polyadmin/templates/admin/resource/delete.html +29 -0
  85. polyadmin/templates/admin/resource/delete_selected.html +49 -0
  86. polyadmin/templates/admin/resource/detail.html +78 -0
  87. polyadmin/templates/admin/resource/form.html +5 -0
  88. polyadmin/templates/admin/resource/list.html +5 -0
  89. polyadmin/templates/admin/theme.html +372 -0
  90. polyadmin/templates/admin/widgets/activity.html +8 -0
  91. polyadmin/templates/admin/widgets/chart.html +15 -0
  92. polyadmin/templates/admin/widgets/donut.html +59 -0
  93. polyadmin/templates/admin/widgets/metric.html +1 -0
  94. polyadmin/templates/admin/widgets/progress.html +7 -0
  95. polyadmin/templates/admin/widgets/stat.html +22 -0
  96. polyadmin/templates/admin/widgets/table.html +29 -0
  97. polyadmin/templates/admin/widgets/tabs.html +34 -0
  98. polyadmin/templates/admin/widgets/timeline.html +21 -0
  99. polyadmin/templating.py +528 -0
  100. polyadmin/ui.py +817 -0
  101. polyadmin-0.1.0b1.dist-info/METADATA +239 -0
  102. polyadmin-0.1.0b1.dist-info/RECORD +104 -0
  103. polyadmin-0.1.0b1.dist-info/WHEEL +4 -0
  104. polyadmin-0.1.0b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,93 @@
1
+ """Error responses.
2
+
3
+ Every failure the admin can produce used to be a bare text body --
4
+ `HTMLResponse("Permission denied.", status_code=403)` and friends.
5
+ Someone signed into a themed admin who followed a stale link got a
6
+ white page with three words on it, no navigation, and no way back.
7
+ These render the same failures as an actual page.
8
+
9
+ Deliberately renderer-independent: the page needs the site title and
10
+ the base path and nothing else, so the handlers that never took a
11
+ Renderer and the CSRF route class can all report errors without
12
+ threading one through.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from functools import lru_cache
18
+ from typing import Any
19
+
20
+ from fastapi import Request
21
+ from fastapi.responses import HTMLResponse
22
+
23
+ from polyadmin.fastapi.responses import is_htmx_request
24
+ from polyadmin.i18n import N_, gettext
25
+
26
+ FORBIDDEN = (N_("Permission denied"), N_("Your account doesn't have permission to do that."))
27
+ NOT_FOUND = (N_("Not found"), N_("That record doesn't exist, or it was deleted."))
28
+ UNAUTHENTICATED = (N_("Sign-in required"), N_("You need to be signed in to view this page."))
29
+ CSRF_FAILED = (
30
+ N_("Security check failed"),
31
+ N_("This page expired before the form was submitted. Reload and try again."),
32
+ )
33
+
34
+
35
+ @lru_cache(maxsize=1)
36
+ def _renderer():
37
+ # Built once: the error page is request-independent apart from the
38
+ # status, the message, and two strings off the Admin. Imported here
39
+ # rather than at module scope to keep this module importable from
40
+ # templating.py's own dependencies without a cycle.
41
+ from polyadmin.templating import Renderer
42
+
43
+ return Renderer()
44
+
45
+
46
+ def error_response(
47
+ request: Request,
48
+ admin: Any,
49
+ base_path: str,
50
+ status: int,
51
+ title: str,
52
+ message: str,
53
+ ) -> HTMLResponse:
54
+ """Render a failure as a page -- or, for an htmx request, as just the
55
+ alert, since a whole document swapped into a table cell is nonsense.
56
+ """
57
+ context = {
58
+ "site_title": gettext(getattr(admin, "site_title", "") or "PolyAdmin"),
59
+ "status": status,
60
+ "title": gettext(title),
61
+ "message": gettext(message),
62
+ # No point offering the link when an unauthenticated visitor
63
+ # cannot reach the dashboard either.
64
+ "home_url": "" if status == 401 else base_path,
65
+ }
66
+ template = (
67
+ "admin/components/error_fragment.html" if is_htmx_request(request) else "admin/error.html"
68
+ )
69
+ try:
70
+ renderer = getattr(request.state, "renderer", None) or _renderer()
71
+ html = renderer.render(template, context)
72
+ except Exception: # noqa: BLE001 -- see below
73
+ # The error page itself failed to build. Fall back to the plain
74
+ # body rather than returning nothing at all -- an ugly 403 beats
75
+ # a blank 500 that hides which failure actually happened.
76
+ return HTMLResponse(message, status_code=status)
77
+ return HTMLResponse(html, status_code=status)
78
+
79
+
80
+ def forbidden(request: Request, admin: Any, base_path: str) -> HTMLResponse:
81
+ return error_response(request, admin, base_path, 403, *FORBIDDEN)
82
+
83
+
84
+ def not_found(request: Request, admin: Any, base_path: str) -> HTMLResponse:
85
+ return error_response(request, admin, base_path, 404, *NOT_FOUND)
86
+
87
+
88
+ def unauthenticated(request: Request, admin: Any, base_path: str) -> HTMLResponse:
89
+ return error_response(request, admin, base_path, 401, *UNAUTHENTICATED)
90
+
91
+
92
+ def csrf_failure(request: Request, admin: Any, base_path: str) -> HTMLResponse:
93
+ return error_response(request, admin, base_path, 403, *CSRF_FAILED)