django-api-admin 1.2.0__tar.gz → 1.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.
Files changed (92) hide show
  1. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/PKG-INFO +1 -1
  2. django_api_admin-1.2.1/django_api_admin/__init__.py +47 -0
  3. django_api_admin-1.2.1/django_api_admin/actions.py +40 -0
  4. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/__init__.py +0 -0
  5. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/admin_api_root.py +23 -0
  6. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/admin_log.py +83 -0
  7. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/app_index.py +62 -0
  8. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/autocomplete.py +155 -0
  9. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/index.py +37 -0
  10. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/language_catalog.py +98 -0
  11. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/obtain_token.py +95 -0
  12. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/password_change.py +77 -0
  13. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/site_context.py +29 -0
  14. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/token_refresh.py +7 -0
  15. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/user_information.py +40 -0
  16. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/view_on_site.py +122 -0
  17. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/__init__.py +0 -0
  18. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/add.py +104 -0
  19. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/change.py +208 -0
  20. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/changelist.py +176 -0
  21. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/delete.py +104 -0
  22. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/detail.py +60 -0
  23. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/handle_action.py +105 -0
  24. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/history.py +52 -0
  25. django_api_admin-1.2.1/django_api_admin/admin_views/model_admin_views/list.py +36 -0
  26. django_api_admin-1.2.1/django_api_admin/admins/__init__.py +0 -0
  27. django_api_admin-1.2.1/django_api_admin/admins/base_admin.py +284 -0
  28. django_api_admin-1.2.1/django_api_admin/admins/inline_admin.py +87 -0
  29. django_api_admin-1.2.1/django_api_admin/admins/model_admin.py +593 -0
  30. django_api_admin-1.2.1/django_api_admin/apps.py +27 -0
  31. django_api_admin-1.2.1/django_api_admin/changelist.py +490 -0
  32. django_api_admin-1.2.1/django_api_admin/checks.py +1264 -0
  33. django_api_admin-1.2.1/django_api_admin/constants/__init__.py +0 -0
  34. django_api_admin-1.2.1/django_api_admin/constants/field_attributes.py +82 -0
  35. django_api_admin-1.2.1/django_api_admin/constants/vars.py +12 -0
  36. django_api_admin-1.2.1/django_api_admin/declarations/__init__.py +0 -0
  37. django_api_admin-1.2.1/django_api_admin/declarations/functions.py +305 -0
  38. django_api_admin-1.2.1/django_api_admin/decorators.py +108 -0
  39. django_api_admin-1.2.1/django_api_admin/exceptions.py +31 -0
  40. django_api_admin-1.2.1/django_api_admin/filters.py +554 -0
  41. django_api_admin-1.2.1/django_api_admin/hooks.py +67 -0
  42. django_api_admin-1.2.1/django_api_admin/migrations/0001_initial.py +42 -0
  43. django_api_admin-1.2.1/django_api_admin/migrations/__init__.py +0 -0
  44. django_api_admin-1.2.1/django_api_admin/models.py +194 -0
  45. django_api_admin-1.2.1/django_api_admin/openapi.py +303 -0
  46. django_api_admin-1.2.1/django_api_admin/options.py +287 -0
  47. django_api_admin-1.2.1/django_api_admin/pagination.py +24 -0
  48. django_api_admin-1.2.1/django_api_admin/permissions.py +10 -0
  49. django_api_admin-1.2.1/django_api_admin/serializers.py +399 -0
  50. django_api_admin-1.2.1/django_api_admin/sites.py +510 -0
  51. django_api_admin-1.2.1/django_api_admin/utils/__init__.py +0 -0
  52. django_api_admin-1.2.1/django_api_admin/utils/_get_non_gfk_field.py +30 -0
  53. django_api_admin-1.2.1/django_api_admin/utils/diff_helper.py +46 -0
  54. django_api_admin-1.2.1/django_api_admin/utils/flatten.py +11 -0
  55. django_api_admin-1.2.1/django_api_admin/utils/force_login.py +14 -0
  56. django_api_admin-1.2.1/django_api_admin/utils/get_content_type_for_model.py +6 -0
  57. django_api_admin-1.2.1/django_api_admin/utils/get_deleted_objects.py +67 -0
  58. django_api_admin-1.2.1/django_api_admin/utils/get_field_attributes.py +54 -0
  59. django_api_admin-1.2.1/django_api_admin/utils/get_fields_from_path.py +22 -0
  60. django_api_admin-1.2.1/django_api_admin/utils/get_form_config.py +13 -0
  61. django_api_admin-1.2.1/django_api_admin/utils/get_form_fields.py +46 -0
  62. django_api_admin-1.2.1/django_api_admin/utils/get_inline_by_field_name.py +12 -0
  63. django_api_admin-1.2.1/django_api_admin/utils/get_inlines.py +51 -0
  64. django_api_admin-1.2.1/django_api_admin/utils/get_model_from_relation.py +8 -0
  65. django_api_admin-1.2.1/django_api_admin/utils/get_related_name.py +10 -0
  66. django_api_admin-1.2.1/django_api_admin/utils/label_for_field.py +70 -0
  67. django_api_admin-1.2.1/django_api_admin/utils/lookup_field.py +29 -0
  68. django_api_admin-1.2.1/django_api_admin/utils/lookup_spawns_duplicates.py +28 -0
  69. django_api_admin-1.2.1/django_api_admin/utils/model_format_dict.py +17 -0
  70. django_api_admin-1.2.1/django_api_admin/utils/model_ngettext.py +39 -0
  71. django_api_admin-1.2.1/django_api_admin/utils/nested_objects.py +71 -0
  72. django_api_admin-1.2.1/django_api_admin/utils/prepare_lookup_value.py +11 -0
  73. django_api_admin-1.2.1/django_api_admin/utils/quote.py +22 -0
  74. django_api_admin-1.2.1/django_api_admin/utils/remove_field.py +12 -0
  75. django_api_admin-1.2.1/django_api_admin/utils/reverse_field_path.py +34 -0
  76. django_api_admin-1.2.1/django_api_admin/utils/url_params_from_lookup_dict.py +18 -0
  77. django_api_admin-1.2.1/django_api_admin/utils/validate_bulk_edits.py +105 -0
  78. django_api_admin-1.2.1/django_api_admin/utils/validate_inline_field_names.py +25 -0
  79. django_api_admin-1.2.1/django_api_admin/views/__init__.py +0 -0
  80. django_api_admin-1.2.1/django_api_admin/views/admin_views.py +677 -0
  81. django_api_admin-1.2.1/django_api_admin/views/site_views.py +251 -0
  82. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/django_api_admin.egg-info/PKG-INFO +1 -1
  83. django_api_admin-1.2.1/django_api_admin.egg-info/SOURCES.txt +88 -0
  84. django_api_admin-1.2.1/django_api_admin.egg-info/top_level.txt +2 -0
  85. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/pyproject.toml +4 -2
  86. django_api_admin-1.2.0/django_api_admin.egg-info/SOURCES.txt +0 -8
  87. django_api_admin-1.2.0/django_api_admin.egg-info/top_level.txt +0 -1
  88. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/LICENSE +0 -0
  89. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/README.md +0 -0
  90. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/django_api_admin.egg-info/dependency_links.txt +0 -0
  91. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/django_api_admin.egg-info/requires.txt +0 -0
  92. {django_api_admin-1.2.0 → django_api_admin-1.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-api-admin
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: A RESTful API implementation of django.contrib.admin, designed for writing custom frontends.
5
5
  Author-email: Muhammad Salah <msbizzacc0unt@outlook.com>
6
6
  License: MIT License
@@ -0,0 +1,47 @@
1
+ from django.utils.module_loading import autodiscover_modules
2
+
3
+ from django_api_admin.decorators import action, display, register
4
+ from django_api_admin.filters import (
5
+ AllValuesFieldListFilter,
6
+ BooleanFieldListFilter,
7
+ ChoicesFieldListFilter,
8
+ DateFieldListFilter,
9
+ EmptyFieldListFilter,
10
+ FieldListFilter,
11
+ ListFilter,
12
+ RelatedFieldListFilter,
13
+ RelatedOnlyFieldListFilter,
14
+ SimpleListFilter,
15
+ )
16
+ from django_api_admin.constants.vars import HORIZONTAL, VERTICAL
17
+ from django_api_admin.admins.model_admin import APIModelAdmin
18
+ from django_api_admin.admins.inline_admin import StackedInlineAPI, TabularInlineAPI
19
+ from django_api_admin.sites import APIAdminSite, site
20
+
21
+ __all__ = [
22
+ "action",
23
+ "display",
24
+ "register",
25
+ "APIModelAdmin",
26
+ "HORIZONTAL",
27
+ "VERTICAL",
28
+ "StackedInlineAPI",
29
+ "TabularInlineAPI",
30
+ "APIAdminSite",
31
+ "site",
32
+ "ListFilter",
33
+ "SimpleListFilter",
34
+ "FieldListFilter",
35
+ "BooleanFieldListFilter",
36
+ "RelatedFieldListFilter",
37
+ "ChoicesFieldListFilter",
38
+ "DateFieldListFilter",
39
+ "AllValuesFieldListFilter",
40
+ "EmptyFieldListFilter",
41
+ "RelatedOnlyFieldListFilter",
42
+ "autodiscover",
43
+ ]
44
+
45
+
46
+ def autodiscover():
47
+ autodiscover_modules("admin", register_to=site)
@@ -0,0 +1,40 @@
1
+ from django.utils.translation import gettext_lazy, gettext as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.exceptions import PermissionDenied
5
+ from rest_framework.response import Response
6
+
7
+ from django_api_admin.utils.model_ngettext import model_ngettext
8
+ from django_api_admin.utils.get_deleted_objects import get_deleted_objects
9
+ from django_api_admin.decorators import action
10
+
11
+
12
+ @action(
13
+ permissions=['delete'],
14
+ description=gettext_lazy('Delete selected %(verbose_name_plural)s')
15
+ )
16
+ def delete_selected(modeladmin, request, queryset):
17
+ """
18
+ default api_admin action deletes the selected objects
19
+ no confirmation page
20
+ """
21
+ _deletable_objects, _model_count, perms_needed, _protected = get_deleted_objects(
22
+ queryset, request, modeladmin.admin_site)
23
+
24
+ # check the permissions
25
+ if perms_needed:
26
+ objects_name = model_ngettext(queryset)
27
+ msg = _("Cannot delete %(name)s") % {"name": objects_name}
28
+ raise PermissionDenied(detail=msg)
29
+
30
+ # log the deletion of all the objects inside the queryset
31
+ n = queryset.count()
32
+ if n:
33
+ for obj in queryset:
34
+ modeladmin.log_deletion(request, obj, str(obj))
35
+
36
+ # delete the queryset
37
+ queryset.delete()
38
+ msg = _("Successfully deleted %s %s.") % (
39
+ n, model_ngettext(modeladmin.opts, n))
40
+ return Response({'detail': msg}, status=status.HTTP_200_OK)
@@ -0,0 +1,23 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.response import Response
5
+ from rest_framework.views import APIView
6
+ from rest_framework.reverse import reverse
7
+
8
+
9
+ class AdminAPIRootView(APIView):
10
+ """
11
+ A list of all root urls in django_api_admin
12
+ """
13
+ root_urls = None
14
+
15
+ def get(self, request, *args, **kwargs):
16
+ namespace = request.resolver_match.namespace
17
+ data = dict()
18
+
19
+ for url in self.root_urls:
20
+ data[url.name] = reverse(
21
+ namespace + ':' + url.name, args=args, kwargs=kwargs, request=request)
22
+
23
+ return Response(data or {}, status=status.HTTP_200_OK)
@@ -0,0 +1,83 @@
1
+ import json
2
+
3
+ from django.utils.translation import gettext_lazy as _
4
+
5
+ from rest_framework import status
6
+ from rest_framework.response import Response
7
+ from rest_framework.views import APIView
8
+
9
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
10
+
11
+ from django_api_admin.models import LogEntry
12
+ from django_api_admin.openapi import CommonAPIResponses
13
+ from django_api_admin.serializers import LogEntrySerializer, AdminLogRequestSerializer
14
+
15
+
16
+ class AdminLogView(APIView):
17
+ """
18
+ Returns a list of actions that were preformed using django admin.
19
+ """
20
+ serializer_class = None
21
+ pagination_class = None
22
+ permission_classes = []
23
+ ordering_fields = ['action_time', '-action_time']
24
+ admin_site = None
25
+
26
+ @extend_schema(
27
+ methods=['GET'],
28
+ parameters=[AdminLogRequestSerializer],
29
+ responses={
30
+ 200: OpenApiResponse(
31
+ response=LogEntrySerializer(many=True),
32
+ description=_('Successfully retrieved admin log entries')
33
+ ),
34
+ 401: CommonAPIResponses.unauthorized(),
35
+ 403: CommonAPIResponses.permission_denied(),
36
+ },
37
+ description=_('Retrieve a list of admin log entries'),
38
+ tags=['admin-log']
39
+ )
40
+ def get(self, request):
41
+ queryset = LogEntry.objects.all()
42
+
43
+ # order the queryset
44
+ try:
45
+ ordering = self.request.query_params.get('o')
46
+ if ordering is not None:
47
+ if ordering not in self.ordering_fields:
48
+ raise KeyError
49
+ queryset = queryset.order_by(ordering)
50
+ except:
51
+ return Response({'detail': _('Wrong ordering field set.')}, status=status.HTTP_400_BAD_REQUEST)
52
+
53
+ # filter the queryset.
54
+ try:
55
+ object_id = self.request.query_params.get('object_id')
56
+ if object_id is not None:
57
+ queryset = queryset.filter(object_id=object_id)
58
+ except:
59
+ return Response({'detail': _('Bad filters.')}, status=status.HTTP_400_BAD_REQUEST)
60
+
61
+ # paginate queryset.
62
+ paginator = self.pagination_class()
63
+ page = paginator.paginate_queryset(queryset, request, view=self)
64
+
65
+ # serialize queryset.
66
+ serializer = self.serializer_class(page, many=True)
67
+
68
+ return Response({
69
+ 'action_list': self.serialize_messages(serializer.data),
70
+ 'config': self.get_config(page, queryset)},
71
+ status=status.HTTP_200_OK)
72
+
73
+ def serialize_messages(self, data):
74
+ for idx, item in enumerate(data, start=0):
75
+ data[idx]['change_message'] = json.loads(
76
+ item['change_message'] or '[]')
77
+ return data
78
+
79
+ def get_config(self, page, queryset):
80
+ return {
81
+ 'result_count': len(page),
82
+ 'full_result_count': queryset.count(),
83
+ }
@@ -0,0 +1,62 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework.response import Response
4
+ from rest_framework import status
5
+ from rest_framework.exceptions import ParseError
6
+
7
+ from rest_framework.views import APIView
8
+
9
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
10
+
11
+ from django_api_admin.serializers import AppIndexSerializer, AppSerializer
12
+ from django_api_admin.openapi import CommonAPIResponses
13
+
14
+
15
+ class AppIndexView(APIView):
16
+ """
17
+ Lists models inside a given app.
18
+ """
19
+ serializer_class = AppIndexSerializer
20
+ permission_classes = []
21
+ admin_site = None
22
+
23
+ @extend_schema(
24
+ request=AppIndexSerializer,
25
+ responses={
26
+ 200: OpenApiResponse(
27
+ response=AppSerializer,
28
+ description=_(
29
+ "Successfully constructed the list of registered models")
30
+ ),
31
+ 403: CommonAPIResponses.permission_denied(),
32
+ 401: CommonAPIResponses.unauthorized()
33
+ }
34
+ )
35
+ def get(self, request, app_label):
36
+ serializer = self.get_serializer(app_label)
37
+ if not serializer.is_valid():
38
+ raise ParseError({"detail": _("invalid app_label")})
39
+
40
+ app_dict = self.admin_site._build_app_dict(request, app_label)
41
+
42
+ if not app_dict:
43
+ return Response({'detail': _('The requested admin page does not exist.')},
44
+ status=status.HTTP_404_NOT_FOUND)
45
+
46
+ # Sort the models alphabetically within each app.
47
+ app_dict['models'].sort(key=lambda x: x['name'])
48
+
49
+ data = {
50
+ 'app_label': app_label,
51
+ 'app': app_dict,
52
+ }
53
+ return Response(data, status=status.HTTP_200_OK)
54
+
55
+ def get_serializer(self, app_label):
56
+ registered_app_labels = {
57
+ model._meta.app_label for model in self.admin_site._registry.keys()
58
+ }
59
+ return AppIndexSerializer(
60
+ data={"app_label": app_label},
61
+ context={'registered_app_labels': registered_app_labels}
62
+ )
@@ -0,0 +1,155 @@
1
+ from django.apps import apps
2
+ from django.utils.translation import gettext_lazy as _
3
+ from django.core.exceptions import FieldDoesNotExist
4
+
5
+ from rest_framework.exceptions import PermissionDenied, ParseError
6
+ from rest_framework.views import APIView
7
+ from rest_framework.response import Response
8
+ from rest_framework import status
9
+ from rest_framework.views import APIView
10
+
11
+ from drf_spectacular.utils import extend_schema, OpenApiExample, OpenApiResponse
12
+
13
+ from django_api_admin.serializers import AutoCompleteSerializer
14
+ from django_api_admin.openapi import CommonAPIResponses
15
+
16
+
17
+ class AutoCompleteView(APIView):
18
+ """
19
+ API view for handling autocomplete functionality in admin fields.
20
+ """
21
+ permission_classes = []
22
+ admin_site = None
23
+
24
+ @extend_schema(
25
+ parameters=[AutoCompleteSerializer],
26
+ responses={
27
+ 200: OpenApiResponse(
28
+ description=_("Successful autocomplete response"),
29
+ response=AutoCompleteSerializer,
30
+ examples=[
31
+ OpenApiExample(
32
+ name=_("Success Response"),
33
+ summary=_(
34
+ "Example of a successful autocomplete response"),
35
+ description="Returns matching records based on the search term",
36
+ value=[{
37
+ "id": 1,
38
+ "name": "Muhammad",
39
+ "age": 60,
40
+ "is_vip": True,
41
+ "date_joined": "2025-02-02T23:09:31.994853Z",
42
+ "title": None,
43
+ "user": 1,
44
+ "publisher": [1],
45
+ "pk": 1
46
+ }],
47
+ status_codes=["200"],
48
+ )
49
+ ]
50
+ ),
51
+ 403: CommonAPIResponses.permission_denied(),
52
+ 401: CommonAPIResponses.unauthorized(),
53
+ },
54
+ description=_(
55
+ "Endpoint for autocomplete functionality on model fields")
56
+ )
57
+ def get(self, request):
58
+ """
59
+ Process the request to extract search parameters,
60
+ validates user permissions, retrieves the relevant queryset,
61
+ paginates the results, and returns them as a JSON response.
62
+ """
63
+ (
64
+ self.term,
65
+ self.model_admin,
66
+ self.source_field,
67
+ to_field_name,
68
+ ) = self.process_request(request)
69
+
70
+ if not self.has_perm(request):
71
+ raise PermissionDenied
72
+
73
+ self.queryset = self.get_queryset()
74
+ page = self.admin_site.paginate_queryset(
75
+ self.queryset, request, view=self)
76
+
77
+ # serialize data
78
+ serializer_class = self.model_admin.get_serializer_class()
79
+ serializer = serializer_class(page, many=True)
80
+ data = serializer.data
81
+
82
+ return Response(
83
+ data,
84
+ status=status.HTTP_200_OK
85
+ )
86
+
87
+ def get_queryset(self):
88
+ """Return queryset based on model_admin.get_search_results()."""
89
+ qs = self.model_admin.get_queryset()
90
+ qs = qs.complex_filter(self.source_field.get_limit_choices_to())
91
+ qs, search_use_distinct = self.model_admin.get_search_results(
92
+ qs, self.term)
93
+ if search_use_distinct:
94
+ qs = qs.distinct()
95
+ return qs
96
+
97
+ def process_request(self, request):
98
+ """
99
+ Validate request integrity, extract and return request parameters.
100
+
101
+ Since the subsequent view permission check requires the target model
102
+ admin, which is determined here, raise PermissionDenied if the
103
+ requested app, model or field are malformed.
104
+
105
+ Raise Http404 if the target model admin is not configured properly with
106
+ search_fields.
107
+ """
108
+ term = request.GET.get("term", "")
109
+
110
+ try:
111
+ app_label = request.GET["app_label"]
112
+ model_name = request.GET["model_name"]
113
+ field_name = request.GET["field_name"]
114
+ except KeyError:
115
+ raise ParseError(
116
+ {'detail': _('missing values app_label, model_name, and field_name')})
117
+
118
+ # Retrieve objects from parameters.
119
+ try:
120
+ source_model = apps.get_model(app_label, model_name)
121
+ except LookupError:
122
+ raise ParseError({'detail': _('source model not found')})
123
+ try:
124
+ source_field = source_model._meta.get_field(field_name)
125
+ except FieldDoesNotExist:
126
+ raise ParseError(
127
+ {f'detail': _(f'source field not found in source model {source_model._meta.verbose_name}')})
128
+ try:
129
+ remote_model = source_field.remote_field.model
130
+ except AttributeError:
131
+ raise ParseError(
132
+ {'detail': _(f'unable to locate the related model using source field {source_field.name}')})
133
+ try:
134
+ model_admin = self.admin_site._registry[remote_model]
135
+ except KeyError:
136
+ raise ParseError(
137
+ {'detail': _('the remote model is not registered in the admin')})
138
+
139
+ # Validate suitability of objects.
140
+ if not getattr(model_admin, "search_fields"):
141
+ raise ParseError(_('%s must have search_fields for the autocomplete_view."') % type(
142
+ model_admin).__qualname__)
143
+
144
+ to_field_name = getattr(
145
+ source_field.remote_field, "field_name", remote_model._meta.pk.attname
146
+ )
147
+ to_field_name = remote_model._meta.get_field(to_field_name).attname
148
+ if not model_admin.to_field_allowed(to_field_name):
149
+ raise PermissionDenied
150
+
151
+ return term, model_admin, source_field, to_field_name
152
+
153
+ def has_perm(self, request):
154
+ """Check if user has permission to access the related model."""
155
+ return self.model_admin.has_view_permission(request)
@@ -0,0 +1,37 @@
1
+ # from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.response import Response
5
+ from rest_framework.reverse import reverse
6
+ from rest_framework.views import APIView
7
+
8
+ from drf_spectacular.utils import extend_schema
9
+
10
+ from django_api_admin.serializers import AppListSerializer
11
+ from django_api_admin.openapi import CommonAPIResponses
12
+
13
+
14
+ class IndexView(APIView):
15
+ """
16
+ Return json object that lists all the installed
17
+ apps that have been registered by the admin site.
18
+ """
19
+ permission_classes = []
20
+ admin_site = None
21
+
22
+ @extend_schema(
23
+ responses={
24
+ 200: AppListSerializer,
25
+ 403: CommonAPIResponses.permission_denied(),
26
+ 401: CommonAPIResponses.unauthorized()
27
+ },
28
+ )
29
+ def get(self, request):
30
+ app_list = self.admin_site.get_app_list(request)
31
+ # add an url to app_index in every app in app_list
32
+ for app in app_list:
33
+ app['url'] = reverse(f'{self.admin_site.name}:app_list', kwargs={
34
+ 'app_label': app['app_label']}, request=request)
35
+ data = {'app_list': app_list}
36
+ request.current_app = self.admin_site.name
37
+ return Response(data, status=status.HTTP_200_OK)
@@ -0,0 +1,98 @@
1
+
2
+ from django.utils.translation import gettext_lazy as _
3
+ import json
4
+
5
+ from django.views.i18n import JSONCatalog
6
+
7
+ from rest_framework.response import Response
8
+ from rest_framework.views import APIView
9
+
10
+ from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample
11
+
12
+ from django_api_admin.serializers import LanguageCatalogSerializer
13
+ from django_api_admin.openapi import CommonAPIResponses
14
+
15
+
16
+ class LanguageCatalogView(APIView):
17
+ """
18
+ Returns json object with i18n translation catalog
19
+ to be used by a client site javascript library
20
+ """
21
+ permission_classes = []
22
+ admin_site = None
23
+
24
+ @extend_schema(
25
+ responses={
26
+ 200: OpenApiResponse(
27
+ response=LanguageCatalogSerializer,
28
+ description=_("Successful retrieval of the language catalog."),
29
+ examples=[
30
+ OpenApiExample(
31
+ name=_("Success Response"),
32
+ summary=_(
33
+ "Example of a successful language catalog request"),
34
+ description=_(
35
+ "return the translation string used in this app"),
36
+ value={
37
+ "catalog": {
38
+ "AM": "ص",
39
+ "PM": "م",
40
+ "January": "يناير",
41
+ "February": "فبراير"
42
+ },
43
+ "formats": {
44
+ "DATE_FORMAT": "j F، Y",
45
+ "DATETIME_FORMAT": "N j, Y, P",
46
+ "TIME_FORMAT": "g:i A",
47
+ "YEAR_MONTH_FORMAT": "F Y",
48
+ "MONTH_DAY_FORMAT": "j F",
49
+ "SHORT_DATE_FORMAT": "d/m/Y",
50
+ "SHORT_DATETIME_FORMAT": "m/d/Y P",
51
+ "FIRST_DAY_OF_WEEK": 0,
52
+ "DECIMAL_SEPARATOR": ",",
53
+ "THOUSAND_SEPARATOR": ".",
54
+ "NUMBER_GROUPING": 0,
55
+ "DATE_INPUT_FORMATS": [
56
+ "%Y-%m-%d",
57
+ "%m/%d/%Y",
58
+ "%m/%d/%y",
59
+ "%b %d %Y",
60
+ "%b %d, %Y",
61
+ "%d %b %Y",
62
+ "%d %b, %Y",
63
+ "%B %d %Y",
64
+ "%B %d, %Y",
65
+ "%d %B %Y",
66
+ "%d %B, %Y"
67
+ ],
68
+ "TIME_INPUT_FORMATS": [
69
+ "%H:%M:%S",
70
+ "%H:%M:%S.%f",
71
+ "%H:%M"
72
+ ],
73
+ "DATETIME_INPUT_FORMATS": [
74
+ "%Y-%m-%d %H:%M:%S",
75
+ "%Y-%m-%d %H:%M:%S.%f",
76
+ "%Y-%m-%d %H:%M",
77
+ "%m/%d/%Y %H:%M:%S",
78
+ "%m/%d/%Y %H:%M:%S.%f",
79
+ "%m/%d/%Y %H:%M",
80
+ "%m/%d/%y %H:%M:%S",
81
+ "%m/%d/%y %H:%M:%S.%f",
82
+ "%m/%d/%y %H:%M"
83
+ ]
84
+ },
85
+ "plural": "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5",
86
+ },
87
+ status_codes=["200"],
88
+ )
89
+ ]
90
+ ),
91
+ 403: CommonAPIResponses.permission_denied(),
92
+ 401: CommonAPIResponses.unauthorized(),
93
+ }
94
+ )
95
+ def get(self, request):
96
+ response = JSONCatalog.as_view(
97
+ packages=['django_api_admin'], domain='django')(request)
98
+ return Response(json.loads(response.content), status=response.status_code)
@@ -0,0 +1,95 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.response import Response
5
+ from rest_framework.views import APIView
6
+
7
+ from rest_framework_simplejwt.tokens import RefreshToken
8
+
9
+ from drf_spectacular.utils import extend_schema, OpenApiExample, OpenApiResponse
10
+
11
+ from django_api_admin.utils.get_form_fields import get_form_fields
12
+ from django_api_admin.openapi import CommonAPIResponses, APIResponseExamples, User
13
+ from django_api_admin.serializers import FormFieldsSerializer, ObtainTokenResponseSerializer
14
+
15
+
16
+ class ObtainTokenView(APIView):
17
+ """
18
+ Allow users to login using username and password.
19
+ """
20
+ serializer_class = None
21
+ permission_classes = []
22
+ admin_site = None
23
+
24
+ @extend_schema(
25
+ responses={
26
+ 200: OpenApiResponse(
27
+ description=_(
28
+ "Successfully returned the field attributes list"),
29
+ response=FormFieldsSerializer,
30
+ examples=[
31
+ APIResponseExamples.field_attributes()
32
+ ]
33
+ ),
34
+ 403: CommonAPIResponses.permission_denied(),
35
+ 401: CommonAPIResponses.unauthorized()
36
+ }
37
+ )
38
+ def get(self, request):
39
+ serializer = self.serializer_class()
40
+ form_fields = get_form_fields(serializer)
41
+ return Response({'fields': form_fields}, status=status.HTTP_200_OK)
42
+
43
+ @extend_schema(
44
+ responses={
45
+ 200: OpenApiResponse(
46
+ description=_("Successful token obtainment"),
47
+ response=ObtainTokenResponseSerializer,
48
+ examples=[
49
+ OpenApiExample(
50
+ name=_("Success Response"),
51
+ summary=_(
52
+ "Example of a successful token obtain response"),
53
+ description=_(
54
+ "Returns a pair of tokens containing both the refresh and access tokens"),
55
+ value={
56
+ "detail": "you are logged in successfully",
57
+ "user": User,
58
+ "tokens": {
59
+ "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTczOTIyODYzMywiaWF0IjoxNzM4NjIzODMzLCJqdGkiOiI0NWFmYTUzYzk4MWY0MjdkODQ5ODgwMGRlOTNiNTY3NSIsInVzZXJfaWQiOjF9.ekHLcEXJRzuim0GlIckd4iFfSiljqfdPpIBgK2_a12s",
60
+ "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzM4NzEwMjMzLCJpYXQiOjE3Mzg2MjM4MzMsImp0aSI6IjkxNjljOWUxNzliMDQ3MmI4NmY0MTJhYzIyOTRkZThiIiwidXNlcl9pZCI6MX0.Gwb23W-clas-K9VfmDeXRNfEBCFRpxVdMpcp3k-fpXM"
61
+ }
62
+ },
63
+ status_codes=["200"]
64
+ )
65
+ ],
66
+ ),
67
+ 403: CommonAPIResponses.permission_denied(),
68
+ 401: CommonAPIResponses.unauthorized()
69
+ }
70
+ )
71
+ def post(self, request):
72
+ serializer = self.serializer_class(
73
+ data=request.data, context={'request': request})
74
+ if serializer.is_valid():
75
+ user = serializer.get_user()
76
+ tokens = self.get_tokens_for_user(user)
77
+ user_serializer = self.admin_site.user_serializer(user)
78
+ data = {
79
+ 'detail': _('you are logged in successfully'),
80
+ 'user': user_serializer.data,
81
+ 'tokens': tokens
82
+ }
83
+ return Response(data, status=status.HTTP_200_OK)
84
+
85
+ for error in serializer.errors.get('non_field_errors', []):
86
+ if error.code == 'permission_denied':
87
+ return Response(serializer.errors, status=status.HTTP_403_FORBIDDEN)
88
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
89
+
90
+ def get_tokens_for_user(self, user):
91
+ refresh = RefreshToken.for_user(user)
92
+ return {
93
+ 'refresh': str(refresh),
94
+ 'access': str(refresh.access_token),
95
+ }