slthcore 0.4.8__tar.gz → 0.4.9__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.

Potentially problematic release.


This version of slthcore might be problematic. Click here for more details.

Files changed (112) hide show
  1. {slthcore-0.4.8/slthcore.egg-info → slthcore-0.4.9}/PKG-INFO +1 -1
  2. {slthcore-0.4.8 → slthcore-0.4.9}/setup.py +1 -1
  3. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/__init__.py +45 -11
  4. {slthcore-0.4.8 → slthcore-0.4.9}/slth/factory.py +5 -5
  5. {slthcore-0.4.8 → slthcore-0.4.9}/slth/forms.py +24 -23
  6. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/commands/api.py +26 -3
  7. {slthcore-0.4.8 → slthcore-0.4.9}/slth/models.py +1 -1
  8. {slthcore-0.4.8 → slthcore-0.4.9}/slth/serializer.py +7 -3
  9. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/js/slth.min.js +8 -8
  10. {slthcore-0.4.8 → slthcore-0.4.9}/slth/utils.py +8 -0
  11. {slthcore-0.4.8 → slthcore-0.4.9}/slth/views.py +1 -1
  12. {slthcore-0.4.8 → slthcore-0.4.9/slthcore.egg-info}/PKG-INFO +1 -1
  13. {slthcore-0.4.8 → slthcore-0.4.9}/MANIFEST.in +0 -0
  14. {slthcore-0.4.8 → slthcore-0.4.9}/setup.cfg +0 -0
  15. {slthcore-0.4.8 → slthcore-0.4.9}/slth/__init__.py +0 -0
  16. {slthcore-0.4.8 → slthcore-0.4.9}/slth/application.py +0 -0
  17. {slthcore-0.4.8 → slthcore-0.4.9}/slth/apps.py +0 -0
  18. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/configure/__main__.py +0 -0
  19. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/__main__.py +0 -0
  20. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/__pycache__/__main__.cpython-312.pyc +0 -0
  21. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/.DS_Store +0 -0
  22. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/.gitignore +0 -0
  23. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/__init__.py +0 -0
  24. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
  25. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/endpoints/__init__.py +0 -0
  26. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
  27. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
  28. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
  29. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
  30. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
  31. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
  32. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
  33. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
  34. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/base.env +0 -0
  35. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/docker-compose.yml +0 -0
  36. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
  37. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
  38. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
  39. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/local.env +0 -0
  40. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/run.sh +0 -0
  41. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
  42. {slthcore-0.4.8 → slthcore-0.4.9}/slth/cmd/init/boilerplate/test.sh +0 -0
  43. {slthcore-0.4.8 → slthcore-0.4.9}/slth/components.py +0 -0
  44. {slthcore-0.4.8 → slthcore-0.4.9}/slth/db/__init__.py +0 -0
  45. {slthcore-0.4.8 → slthcore-0.4.9}/slth/db/generic.py +0 -0
  46. {slthcore-0.4.8 → slthcore-0.4.9}/slth/db/models.py +0 -0
  47. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/auth.py +0 -0
  48. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/deletion.py +0 -0
  49. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/dev.py +0 -0
  50. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/email.py +0 -0
  51. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/job.py +0 -0
  52. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/log.py +0 -0
  53. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/profile.py +0 -0
  54. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/pushsubscription.py +0 -0
  55. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/report.py +0 -0
  56. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/role.py +0 -0
  57. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/task.py +0 -0
  58. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/timezone.py +0 -0
  59. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/user.py +0 -0
  60. {slthcore-0.4.8 → slthcore-0.4.9}/slth/endpoints/whatsappnotification.py +0 -0
  61. {slthcore-0.4.8 → slthcore-0.4.9}/slth/exceptions.py +0 -0
  62. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/__init__.py +0 -0
  63. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/commands/__init__.py +0 -0
  64. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/commands/integration_test.py +0 -0
  65. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/commands/sync.py +0 -0
  66. {slthcore-0.4.8 → slthcore-0.4.9}/slth/management/commands/worker.py +0 -0
  67. {slthcore-0.4.8 → slthcore-0.4.9}/slth/middleware/__init__.py +0 -0
  68. {slthcore-0.4.8 → slthcore-0.4.9}/slth/middleware/timezone.py +0 -0
  69. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0001_initial.py +0 -0
  70. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
  71. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
  72. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0004_alter_profile_photo.py +0 -0
  73. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0005_alter_profile_photo.py +0 -0
  74. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0006_user.py +0 -0
  75. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0007_deletion_log.py +0 -0
  76. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0008_alter_deletion_datetime_alter_log_datetime.py +0 -0
  77. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0009_remove_email_from_email_email_action_email_attempt_and_more.py +0 -0
  78. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0010_email_key_alter_email_action_alter_email_attempt_and_more.py +0 -0
  79. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0011_usertimezone.py +0 -0
  80. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0012_timezone_remove_usertimezone_key_and_more.py +0 -0
  81. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/0013_whatsappnotification.py +0 -0
  82. {slthcore-0.4.8 → slthcore-0.4.9}/slth/migrations/__init__.py +0 -0
  83. {slthcore-0.4.8 → slthcore-0.4.9}/slth/notifications.py +0 -0
  84. {slthcore-0.4.8 → slthcore-0.4.9}/slth/oauth.py +0 -0
  85. {slthcore-0.4.8 → slthcore-0.4.9}/slth/pdf/__init__.py +0 -0
  86. {slthcore-0.4.8 → slthcore-0.4.9}/slth/pdf/tests.py +0 -0
  87. {slthcore-0.4.8 → slthcore-0.4.9}/slth/permissions.py +0 -0
  88. {slthcore-0.4.8 → slthcore-0.4.9}/slth/printer.py +0 -0
  89. {slthcore-0.4.8 → slthcore-0.4.9}/slth/queryset.py +0 -0
  90. {slthcore-0.4.8 → slthcore-0.4.9}/slth/roles.py +0 -0
  91. {slthcore-0.4.8 → slthcore-0.4.9}/slth/selenium/__init__.py +0 -0
  92. {slthcore-0.4.8 → slthcore-0.4.9}/slth/selenium/browser.py +0 -0
  93. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/.DS_Store +0 -0
  94. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/css/.DS_Store +0 -0
  95. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/css/slth.css +0 -0
  96. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/images/placeholder.png +0 -0
  97. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/js/index.min.js +0 -0
  98. {slthcore-0.4.8 → slthcore-0.4.9}/slth/static/js/react.min.js +0 -0
  99. {slthcore-0.4.8 → slthcore-0.4.9}/slth/statistics.py +0 -0
  100. {slthcore-0.4.8 → slthcore-0.4.9}/slth/tasks.py +0 -0
  101. {slthcore-0.4.8 → slthcore-0.4.9}/slth/templates/email.html +0 -0
  102. {slthcore-0.4.8 → slthcore-0.4.9}/slth/templates/index.html +0 -0
  103. {slthcore-0.4.8 → slthcore-0.4.9}/slth/templates/report.html +0 -0
  104. {slthcore-0.4.8 → slthcore-0.4.9}/slth/templates/service-worker.js +0 -0
  105. {slthcore-0.4.8 → slthcore-0.4.9}/slth/templates/signature.html +0 -0
  106. {slthcore-0.4.8 → slthcore-0.4.9}/slth/tests.py +0 -0
  107. {slthcore-0.4.8 → slthcore-0.4.9}/slth/threadlocal.py +0 -0
  108. {slthcore-0.4.8 → slthcore-0.4.9}/slth/tz.py +0 -0
  109. {slthcore-0.4.8 → slthcore-0.4.9}/slth/urls.py +0 -0
  110. {slthcore-0.4.8 → slthcore-0.4.9}/slthcore.egg-info/SOURCES.txt +0 -0
  111. {slthcore-0.4.8 → slthcore-0.4.9}/slthcore.egg-info/dependency_links.txt +0 -0
  112. {slthcore-0.4.8 → slthcore-0.4.9}/slthcore.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: slthcore
3
- Version: 0.4.8
3
+ Version: 0.4.9
4
4
  Summary: API generator based on yml file
5
5
  Home-page: https://github.com/brenokcc
6
6
  Author: Breno Silva
@@ -4,7 +4,7 @@ install_requires = []
4
4
 
5
5
  setup(
6
6
  name='slthcore',
7
- version='0.4.8',
7
+ version='0.4.9',
8
8
  packages=find_packages(),
9
9
  install_requires=install_requires,
10
10
  include_package_data=True,
@@ -1,5 +1,4 @@
1
1
  import io
2
- import json
3
2
  import inspect
4
3
  from ..models import Log
5
4
  from django.apps import apps
@@ -26,10 +25,9 @@ from ..components import (
26
25
  from slth.application import Application as ApplicationConfig
27
26
  from ..exceptions import JsonResponseException, ReadyResponseException
28
27
  from ..utils import build_url, append_url
29
- from ..models import Profile, Log, Job
28
+ from ..models import Log, Job
30
29
  from slth.queryset import QuerySet
31
30
  from slth import ENDPOINTS
32
- from .. import oauth
33
31
  from ..threadlocal import tl
34
32
  from ..tasks import Task
35
33
 
@@ -65,6 +63,7 @@ class Endpoint(metaclass=EnpointMetaclass):
65
63
  cache = cache
66
64
 
67
65
  def __init__(self):
66
+ self.form: Form | ModelForm = None
68
67
  self.base_url = None
69
68
  self.request = None
70
69
  self.source = None
@@ -150,15 +149,15 @@ class Endpoint(metaclass=EnpointMetaclass):
150
149
  elif isinstance(data, Serializer):
151
150
  data = data.contextualize(self.request).settitle(title)
152
151
  elif isinstance(data, FormFactory):
153
- form = self.getform(data.settitle(title).form(self))
154
- if self.request.method == "POST" or (title and self.request.GET.get("form") == form._key):
152
+ self.form = self.getform(data.settitle(title).build(self))
153
+ if self.request.method == "POST" or (title and self.request.GET.get("form") == self.form._key):
155
154
  try:
156
155
  if isinstance(self, DeleteEndpoint):
157
156
  return self.post()
158
157
  else:
159
- self.cleaned_data = form.submit()
160
- if form._message or form._redirect or form._dispose:
161
- return Response(form._message, form._redirect, dispose=form._dispose)
158
+ self.cleaned_data = self.form.submit()
159
+ if self.form._message or self.form._redirect or self.form._dispose:
160
+ return Response(self.form._message, self.form._redirect, dispose=self.form._dispose)
162
161
  else:
163
162
  return self.post()
164
163
  except ValidationError as e:
@@ -166,7 +165,7 @@ class Endpoint(metaclass=EnpointMetaclass):
166
165
  dict(type="error", text="\n".join(e.messages), errors={})
167
166
  )
168
167
  else:
169
- data = form
168
+ data = self.form
170
169
  elif isinstance(data, Form) or isinstance(data, ModelForm):
171
170
  data = data.settitle(title)
172
171
  elif self.request.method == "POST":# and not data:
@@ -337,7 +336,6 @@ class PublicEndpoint(Endpoint):
337
336
  return True
338
337
 
339
338
 
340
-
341
339
  class ModelEndpoint(Endpoint):
342
340
  def __init__(self):
343
341
  self.model = self.__orig_bases__[0].__args__[0]
@@ -503,6 +501,43 @@ class ChildInstanceEndpoint(ChildEndpoint):
503
501
  return Serializer(self.get_instance()).contextualize(self.request)
504
502
 
505
503
 
504
+ class RelationEditEndpoint(Generic[T], ChildEndpoint):
505
+
506
+ def __init__(self, instance):
507
+ self.source = instance
508
+
509
+ def get(self) -> FormFactory:
510
+ return self.formfactory()
511
+
512
+ def formfactory(self) -> FormFactory:
513
+ return FormFactory(self.get_instance())
514
+
515
+ def get_instance(self):
516
+ return self.__orig_bases__[0].__args__[0].objects.get(pk=self.request.GET['id'])
517
+
518
+
519
+ class RelationDeleteEndpoint(Generic[T], ChildEndpoint):
520
+
521
+ def __init__(self, instance):
522
+ self.model = self.__orig_bases__[0].__args__[0]
523
+ self.source = instance
524
+
525
+ def get(self) -> FormFactory:
526
+ return FormFactory(self.get_instance()).fields()
527
+
528
+ def post(self):
529
+ self.get_instance().safe_delete(self.request.user.username)
530
+ return super().post()
531
+
532
+ def formfactory(self) -> FormFactory:
533
+ return FormFactory(self.get_instance())
534
+
535
+ def get_instance(self):
536
+ return self.model.objects.get(pk=self.request.GET['id'])
537
+
538
+
539
+
540
+
506
541
  class Search(Endpoint):
507
542
  def get(self):
508
543
  key = "_options_"
@@ -529,7 +564,6 @@ class Search(Endpoint):
529
564
  return result[0:10]
530
565
 
531
566
 
532
-
533
567
  class Home(PublicEndpoint):
534
568
  class Meta:
535
569
  verbose_name = ""
@@ -3,7 +3,7 @@ from .serializer import Serializer
3
3
 
4
4
 
5
5
  class FormFactory:
6
- def __init__(self, instance, endpoint=None, method='POST'):
6
+ def __init__(self, instance, method='POST'):
7
7
  self._instance = instance
8
8
  self._fieldsets = {}
9
9
  self._values = {}
@@ -48,7 +48,7 @@ class FormFactory:
48
48
  self._append_field(field_name)
49
49
  for k in values:
50
50
  self._append_field(k)
51
- self.setvalue(**values)
51
+ self.values(**values)
52
52
  self._empty = not self._fieldlist
53
53
  return self
54
54
 
@@ -84,7 +84,7 @@ class FormFactory:
84
84
  self._actions.update(kwargs)
85
85
  return self
86
86
 
87
- def setvalue(self, **kwargs) -> 'FormFactory':
87
+ def values(self, **kwargs) -> 'FormFactory':
88
88
  self._values.update(kwargs)
89
89
  return self
90
90
 
@@ -106,7 +106,7 @@ class FormFactory:
106
106
  self._redirect = '.'
107
107
  return self
108
108
 
109
- def form(self, endpoint):
109
+ def build(self, endpoint):
110
110
  from .forms import ModelForm, Form
111
111
 
112
112
  if isinstance(self._instance, Model):
@@ -135,7 +135,7 @@ class FormFactory:
135
135
  for name, queryset in self._choices.items():
136
136
  form.fields[name].queryset = queryset
137
137
  form.fieldsets = self._fieldsets
138
- form.setvalue(**self._values)
138
+ form.values(**self._values)
139
139
  if self._display:
140
140
  serializer = Serializer(self._instance, request=endpoint.request)
141
141
  for title, fields in self._display.items():
@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
6
6
  from django.forms.models import ModelChoiceIterator, ModelMultipleChoiceField
7
7
  from django.forms import fields
8
8
  from django.db.models import Model, QuerySet, Manager
9
- from .models import Token, Profile
9
+ from django.utils.text import slugify
10
10
  from django.db import transaction
11
11
  from django.db.models import Manager
12
12
  from .exceptions import JsonResponseException
@@ -35,7 +35,7 @@ MASKS = dict(
35
35
 
36
36
  class FormController:
37
37
 
38
- def __init__(self, form):
38
+ def __init__(self, form: Form | ModelForm):
39
39
  super().__init__()
40
40
  self.form = form
41
41
  self.controls = dict(hide=[], show=[], reload=[], set={})
@@ -66,7 +66,10 @@ class FormController:
66
66
  v = v.strftime("%Y-%m-%d")
67
67
  self.controls["set"][k] = v
68
68
 
69
- def get(self, name, value, default=None):
69
+ def get(self, field_name, default=None):
70
+ return self.field_value(field_name, self.form.request.GET.get(field_name, default))
71
+
72
+ def field_value(self, name, value, default=None):
70
73
  if value is None:
71
74
  return default
72
75
  else:
@@ -83,28 +86,28 @@ class FormController:
83
86
  self.controls["hide"].clear()
84
87
  self.controls["set"].clear()
85
88
 
86
- def on_change(self, field_name):
89
+ def on_field_change(self, field_name):
87
90
  self.clear()
88
- getattr(self.form._endpoint, f"on_{field_name}_change")(self, self.values())
91
+ value = self.get(field_name)
92
+ getattr(self.form._endpoint, f"on_{field_name}_change")(value)
89
93
  return self.controls
90
94
 
91
-
92
- def get_field_queryset(self, fname, qs):
95
+ def get_field_queryset(self, field_name, queryset):
93
96
  method_attr = None
94
- method_name = f"get_{fname}_queryset"
97
+ method_name = f"get_{field_name}_queryset"
95
98
  if hasattr(self.form._endpoint, method_name):
96
99
  method_attr = getattr(self.form._endpoint, method_name)
97
100
  elif hasattr(self.form, "instance") and hasattr(
98
101
  self.form.instance, method_name
99
102
  ):
100
103
  method_attr = getattr(self.form.instance, method_name)
101
- queryset = method_attr(qs, self.values()) if method_attr else qs
104
+ queryset = method_attr(queryset) if method_attr else queryset
102
105
  return queryset.apply_lookups(self.form.request.user)
103
106
 
104
107
  def values(self):
105
108
  data = dict(**self.controls["set"])
106
109
  for name in self.form.fields:
107
- value = self.get(name, self.form.request.GET.get(name))
110
+ value = self.get(name)
108
111
  if value:
109
112
  data[name] = value
110
113
  return data
@@ -156,7 +159,7 @@ class FormMixin:
156
159
  def to_dict(self, prefix=None):
157
160
  field_name = self.request.GET.get("on_change")
158
161
  if field_name:
159
- raise JsonResponseException(self.controller.on_change(field_name))
162
+ raise JsonResponseException(self.controller.on_field_change(field_name))
160
163
  data = dict(
161
164
  type="form",
162
165
  key=self._key,
@@ -176,7 +179,9 @@ class FormMixin:
176
179
  )
177
180
  if self._display:
178
181
  if isinstance(self._display, Serializer):
179
- # self._display.request = self.request
182
+ self._display.request.GET._mutable = True
183
+ self._display.request.GET.pop('only', None)
184
+ self._display.request.GET._mutable = False
180
185
  data.update(
181
186
  display=self._display.serialize(forward_exception=True)["data"]
182
187
  )
@@ -220,7 +225,7 @@ class FormMixin:
220
225
  fieldsetlist.append(fields[0][0])
221
226
  else:
222
227
  fieldsetlist.append(
223
- dict(type="fieldset", title=title, fields=fields)
228
+ dict(type="fieldset", title=title, name=slugify(title), fields=fields)
224
229
  )
225
230
  data.update(fieldsets=fieldsetlist)
226
231
  else:
@@ -285,7 +290,7 @@ class FormMixin:
285
290
  else:
286
291
  value = None
287
292
  if self.instance is None or self.instance.id is None:
288
- value = field.initial
293
+ value = field.initial or self.initial.get(name)
289
294
  else:
290
295
  value = self.initial.get(name)
291
296
  if callable(value):
@@ -307,7 +312,7 @@ class FormMixin:
307
312
  isinstance(field, ModelChoiceField)
308
313
  or isinstance(field, DjangoModelChoiceField)
309
314
  ):
310
- obj = field.queryset.get(pk=value)
315
+ obj = field.queryset.get(pk=value) if isinstance(value, int) else value
311
316
  value = dict(id=obj.id, label=str(obj).strip())
312
317
  elif isinstance(field, DjangoImageField):
313
318
  value = build_url(self.request, value.url) if value else None
@@ -397,11 +402,9 @@ class FormMixin:
397
402
  cls = ENDPOINTS[self._actions[name]]
398
403
  endpoint = cls.instantiate(self.request, self)
399
404
  if endpoint.check_permission():
400
- data.update(
401
- action=endpoint.get_api_metadata(
402
- self.request, absolute_url(self.request)
403
- )
404
- )
405
+ action=endpoint.get_api_metadata(self.request, absolute_url(self.request))
406
+ action['name'] = action['name'].replace(field.label, "").strip()
407
+ data.update(action=action)
405
408
  return data
406
409
 
407
410
  def submit(self):
@@ -525,7 +528,7 @@ class FormMixin:
525
528
  self._title = title
526
529
  return self
527
530
 
528
- def setvalue(self, **kwargs):
531
+ def values(self, **kwargs):
529
532
  self._values.update(**kwargs)
530
533
  return self
531
534
 
@@ -700,8 +703,6 @@ class CharField(CharField):
700
703
  self.mask = kwargs.pop("mask", None)
701
704
  super().__init__(*args, **kwargs)
702
705
 
703
-
704
-
705
706
 
706
707
  class ChoiceField(ChoiceField):
707
708
 
@@ -14,22 +14,36 @@ class {plural}(endpoints.ListEndpoint[{model}]):
14
14
  def get(self):
15
15
  return (
16
16
  super().get()
17
- .actions('{lower}.cadastrar', '{lower}.editar', '{lower}.excluir')
17
+ .actions('{lower}.cadastrar', '{lower}.visualizar', '{lower}.editar', '{lower}.excluir')
18
18
  )
19
19
 
20
20
 
21
21
  class Cadastrar(endpoints.AddEndpoint[{model}]):
22
22
  class Meta:
23
+ icon = 'plus'
23
24
  verbose_name = 'Cadastrar {verbose_name}'
24
25
 
25
26
  def get(self):
26
27
  return (
27
28
  super().get()
28
29
  )
30
+
31
+
32
+ class Visualizar(endpoints.ViewEndpoint[{model}]):
33
+ class Meta:
34
+ modal = False
35
+ icon = 'eye'
36
+ verbose_name = 'Visualizar {verbose_name}'
37
+
38
+ def get(self):
39
+ return (
40
+ super().get()
41
+ )
29
42
 
30
43
 
31
44
  class Editar(endpoints.EditEndpoint[{model}]):
32
45
  class Meta:
46
+ icon = 'pen'
33
47
  verbose_name = 'Editar {verbose_name}'
34
48
 
35
49
  def get(self):
@@ -40,6 +54,7 @@ class Editar(endpoints.EditEndpoint[{model}]):
40
54
 
41
55
  class Excluir(endpoints.DeleteEndpoint[{model}]):
42
56
  class Meta:
57
+ icon = 'trash'
43
58
  verbose_name = 'Excluir {verbose_name}'
44
59
 
45
60
  def get(self):
@@ -50,10 +65,18 @@ class Excluir(endpoints.DeleteEndpoint[{model}]):
50
65
  """
51
66
 
52
67
  class Command(Command):
68
+
69
+ def add_arguments(self, parser):
70
+ parser.add_argument("models", nargs="*", type=str)
53
71
 
54
72
  def handle(self, *args, **options):
55
- for model in apps.get_models():
56
- if model._meta.app_label == "api":
73
+ names = options.get('models')
74
+ if names:
75
+ models = [apps.get_model(name) for name in names]
76
+ else:
77
+ models = apps.get_models()
78
+ for model in models:
79
+ if names or model._meta.app_label == "api":
57
80
  content = TEMPLATE.format(
58
81
  plural = slugify(model._meta.verbose_name_plural).replace('-de-', '-').replace('-', '').title(),
59
82
  model = model.__name__,
@@ -96,7 +96,7 @@ class RoleFilter(models.Filter):
96
96
 
97
97
  def choices(self, queryset, term=None):
98
98
  application = ApplicationConfig.get_instance()
99
- return [(k, v) for k, v in application.items()]
99
+ return [(k, v) for k, v in application.groups.items()]
100
100
 
101
101
  def filter(self, queryset, value):
102
102
  if value:
@@ -143,10 +143,11 @@ class Serializer:
143
143
  self.metadata['content'].append(('queryset', name, dict(title=title, condition=condition, roles=roles)))
144
144
  return self
145
145
 
146
- def endpoint(self, title, cls, wrap=True, condition=None, roles=()) -> 'Serializer':
146
+ def endpoint(self, title, cls, wrap=False, condition=None, roles=()) -> 'Serializer':
147
+ key = to_snake_case(title) if title else cls.replace('.', '_')
147
148
  if isinstance(cls, str):
148
149
  cls = slth.ENDPOINTS[cls]
149
- self.metadata['content'].append(('endpoint', to_snake_case(title), dict(title=title, cls=cls, wrap=wrap, condition=condition, roles=roles)))
150
+ self.metadata['content'].append(('endpoint', key, dict(title=title, cls=cls, wrap=wrap, condition=condition, roles=roles)))
150
151
  return self
151
152
 
152
153
  def append(self, title, component, condition=None, roles=()) -> 'Serializer':
@@ -217,6 +218,9 @@ class Serializer:
217
218
  if self.request and 'action' in self.request.GET:
218
219
  cls = slth.ENDPOINTS[self.request.GET.get('action')]
219
220
  if cls:### and cls.get_key_name() in self.metadata['allow']:
221
+ self.request.GET._mutable = True
222
+ self.request.GET.pop('action', None)
223
+ self.request.GET._mutable = False
220
224
  endpoint = cls.instantiate(self.request, self.obj)
221
225
  if endpoint.check_permission():
222
226
  raise JsonResponseException(endpoint.serialize())
@@ -234,7 +238,7 @@ class Serializer:
234
238
  if leaf:
235
239
  raise JsonResponseException(actions)
236
240
 
237
- if not self.metadata['content'] and self.obj:
241
+ if not self.metadata['content'] and self.obj and isinstance(self.obj, Model):
238
242
  self.fields(*[field.name for field in type(self.obj)._meta.fields])
239
243
  for m2m in type(self.obj)._meta.many_to_many:
240
244
  self.queryset(m2m.verbose_name, m2m.name)