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

Potentially problematic release.


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

Files changed (127) hide show
  1. {slthcore-0.4.9/slthcore.egg-info → slthcore-0.5.0}/PKG-INFO +1 -1
  2. {slthcore-0.4.9 → slthcore-0.5.0}/setup.py +1 -1
  3. {slthcore-0.4.9 → slthcore-0.5.0}/slth/__init__.py +2 -2
  4. {slthcore-0.4.9 → slthcore-0.5.0}/slth/application.py +78 -16
  5. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/__init__.py +1 -0
  6. {slthcore-0.4.9 → slthcore-0.5.0}/slth/components.py +2 -2
  7. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/__init__.py +28 -22
  8. slthcore-0.5.0/slth/endpoints/settings.py +60 -0
  9. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/user.py +6 -3
  10. {slthcore-0.4.9 → slthcore-0.5.0}/slth/forms.py +12 -5
  11. slthcore-0.5.0/slth/integrations/deepseek/__init__.py +36 -0
  12. slthcore-0.5.0/slth/integrations/google/gemini.py +23 -0
  13. slthcore-0.5.0/slth/integrations/google/places.py +41 -0
  14. slthcore-0.5.0/slth/integrations/google/vision.py +18 -0
  15. slthcore-0.5.0/slth/integrations/justvoip/__init__.py +15 -0
  16. slthcore-0.5.0/slth/integrations/mercadopago/__init__.py +48 -0
  17. slthcore-0.5.0/slth/integrations/openai/chatgpt.py +30 -0
  18. slthcore-0.5.0/slth/integrations/viacep/__init__.py +6 -0
  19. slthcore-0.5.0/slth/integrations/whatsapp/__init__.py +9 -0
  20. slthcore-0.5.0/slth/management/commands/__init__.py +0 -0
  21. slthcore-0.5.0/slth/middleware/__init__.py +0 -0
  22. slthcore-0.5.0/slth/migrations/0014_settings.py +40 -0
  23. slthcore-0.5.0/slth/migrations/__init__.py +0 -0
  24. {slthcore-0.4.9 → slthcore-0.5.0}/slth/models.py +23 -2
  25. {slthcore-0.4.9 → slthcore-0.5.0}/slth/oauth.py +10 -5
  26. {slthcore-0.4.9 → slthcore-0.5.0}/slth/queryset.py +81 -26
  27. {slthcore-0.4.9 → slthcore-0.5.0}/slth/serializer.py +91 -32
  28. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/css/slth.css +14 -7
  29. slthcore-0.5.0/slth/static/js/slth.min.js +270 -0
  30. {slthcore-0.4.9 → slthcore-0.5.0}/slth/templates/index.html +7 -15
  31. {slthcore-0.4.9 → slthcore-0.5.0/slthcore.egg-info}/PKG-INFO +1 -1
  32. {slthcore-0.4.9 → slthcore-0.5.0}/slthcore.egg-info/SOURCES.txt +14 -0
  33. slthcore-0.4.9/slth/static/js/slth.min.js +0 -251
  34. {slthcore-0.4.9 → slthcore-0.5.0}/MANIFEST.in +0 -0
  35. {slthcore-0.4.9 → slthcore-0.5.0}/setup.cfg +0 -0
  36. {slthcore-0.4.9 → slthcore-0.5.0}/slth/apps.py +0 -0
  37. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/configure/__main__.py +0 -0
  38. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/__main__.py +0 -0
  39. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/__pycache__/__main__.cpython-312.pyc +0 -0
  40. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/.DS_Store +0 -0
  41. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/.gitignore +0 -0
  42. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
  43. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/endpoints/__init__.py +0 -0
  44. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
  45. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
  46. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
  47. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
  48. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
  49. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
  50. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
  51. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
  52. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/base.env +0 -0
  53. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/docker-compose.yml +0 -0
  54. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
  55. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
  56. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
  57. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/local.env +0 -0
  58. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/run.sh +0 -0
  59. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
  60. {slthcore-0.4.9 → slthcore-0.5.0}/slth/cmd/init/boilerplate/test.sh +0 -0
  61. {slthcore-0.4.9 → slthcore-0.5.0}/slth/db/__init__.py +0 -0
  62. {slthcore-0.4.9 → slthcore-0.5.0}/slth/db/generic.py +0 -0
  63. {slthcore-0.4.9 → slthcore-0.5.0}/slth/db/models.py +0 -0
  64. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/auth.py +0 -0
  65. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/deletion.py +0 -0
  66. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/dev.py +0 -0
  67. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/email.py +0 -0
  68. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/job.py +0 -0
  69. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/log.py +0 -0
  70. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/profile.py +0 -0
  71. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/pushsubscription.py +0 -0
  72. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/report.py +0 -0
  73. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/role.py +0 -0
  74. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/task.py +0 -0
  75. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/timezone.py +0 -0
  76. {slthcore-0.4.9 → slthcore-0.5.0}/slth/endpoints/whatsappnotification.py +0 -0
  77. {slthcore-0.4.9 → slthcore-0.5.0}/slth/exceptions.py +0 -0
  78. {slthcore-0.4.9 → slthcore-0.5.0}/slth/factory.py +0 -0
  79. {slthcore-0.4.9/slth/management → slthcore-0.5.0/slth/integrations}/__init__.py +0 -0
  80. {slthcore-0.4.9/slth/management/commands → slthcore-0.5.0/slth/integrations/google}/__init__.py +0 -0
  81. {slthcore-0.4.9/slth/middleware → slthcore-0.5.0/slth/integrations/openai}/__init__.py +0 -0
  82. {slthcore-0.4.9/slth/migrations → slthcore-0.5.0/slth/management}/__init__.py +0 -0
  83. {slthcore-0.4.9 → slthcore-0.5.0}/slth/management/commands/api.py +0 -0
  84. {slthcore-0.4.9 → slthcore-0.5.0}/slth/management/commands/integration_test.py +0 -0
  85. {slthcore-0.4.9 → slthcore-0.5.0}/slth/management/commands/sync.py +0 -0
  86. {slthcore-0.4.9 → slthcore-0.5.0}/slth/management/commands/worker.py +0 -0
  87. {slthcore-0.4.9 → slthcore-0.5.0}/slth/middleware/timezone.py +0 -0
  88. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0001_initial.py +0 -0
  89. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
  90. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
  91. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0004_alter_profile_photo.py +0 -0
  92. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0005_alter_profile_photo.py +0 -0
  93. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0006_user.py +0 -0
  94. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0007_deletion_log.py +0 -0
  95. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0008_alter_deletion_datetime_alter_log_datetime.py +0 -0
  96. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0009_remove_email_from_email_email_action_email_attempt_and_more.py +0 -0
  97. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0010_email_key_alter_email_action_alter_email_attempt_and_more.py +0 -0
  98. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0011_usertimezone.py +0 -0
  99. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0012_timezone_remove_usertimezone_key_and_more.py +0 -0
  100. {slthcore-0.4.9 → slthcore-0.5.0}/slth/migrations/0013_whatsappnotification.py +0 -0
  101. {slthcore-0.4.9 → slthcore-0.5.0}/slth/notifications.py +0 -0
  102. {slthcore-0.4.9 → slthcore-0.5.0}/slth/pdf/__init__.py +0 -0
  103. {slthcore-0.4.9 → slthcore-0.5.0}/slth/pdf/tests.py +0 -0
  104. {slthcore-0.4.9 → slthcore-0.5.0}/slth/permissions.py +0 -0
  105. {slthcore-0.4.9 → slthcore-0.5.0}/slth/printer.py +0 -0
  106. {slthcore-0.4.9 → slthcore-0.5.0}/slth/roles.py +0 -0
  107. {slthcore-0.4.9 → slthcore-0.5.0}/slth/selenium/__init__.py +0 -0
  108. {slthcore-0.4.9 → slthcore-0.5.0}/slth/selenium/browser.py +0 -0
  109. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/.DS_Store +0 -0
  110. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/css/.DS_Store +0 -0
  111. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/images/placeholder.png +0 -0
  112. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/js/index.min.js +0 -0
  113. {slthcore-0.4.9 → slthcore-0.5.0}/slth/static/js/react.min.js +0 -0
  114. {slthcore-0.4.9 → slthcore-0.5.0}/slth/statistics.py +0 -0
  115. {slthcore-0.4.9 → slthcore-0.5.0}/slth/tasks.py +0 -0
  116. {slthcore-0.4.9 → slthcore-0.5.0}/slth/templates/email.html +0 -0
  117. {slthcore-0.4.9 → slthcore-0.5.0}/slth/templates/report.html +0 -0
  118. {slthcore-0.4.9 → slthcore-0.5.0}/slth/templates/service-worker.js +0 -0
  119. {slthcore-0.4.9 → slthcore-0.5.0}/slth/templates/signature.html +0 -0
  120. {slthcore-0.4.9 → slthcore-0.5.0}/slth/tests.py +0 -0
  121. {slthcore-0.4.9 → slthcore-0.5.0}/slth/threadlocal.py +0 -0
  122. {slthcore-0.4.9 → slthcore-0.5.0}/slth/tz.py +0 -0
  123. {slthcore-0.4.9 → slthcore-0.5.0}/slth/urls.py +0 -0
  124. {slthcore-0.4.9 → slthcore-0.5.0}/slth/utils.py +0 -0
  125. {slthcore-0.4.9 → slthcore-0.5.0}/slth/views.py +0 -0
  126. {slthcore-0.4.9 → slthcore-0.5.0}/slthcore.egg-info/dependency_links.txt +0 -0
  127. {slthcore-0.4.9 → slthcore-0.5.0}/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.9
3
+ Version: 0.5.0
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.9',
7
+ version='0.5.0',
8
8
  packages=find_packages(),
9
9
  install_requires=install_requires,
10
10
  include_package_data=True,
@@ -64,8 +64,8 @@ class JSONDecoder(json.JSONDecoder):
64
64
  return obj
65
65
 
66
66
 
67
- def dumps(data):
68
- return json.dumps(data, cls=JSONEncoder)
67
+ def dumps(data, indent=1, ensure_ascii=False):
68
+ return json.dumps(data, indent=indent, ensure_ascii=ensure_ascii, cls=JSONEncoder)
69
69
 
70
70
 
71
71
  def loads(data):
@@ -8,7 +8,8 @@ APPLICATION_CLASS = None
8
8
 
9
9
 
10
10
  class Style():
11
- def __init__(self, color="black", background="inherite", border="none"):
11
+ def __init__(self, name, color="black", background="inherite", border="none"):
12
+ self.name = name
12
13
  self.update(color=color, background=background, border=border)
13
14
 
14
15
  def update(self, color=None, background=None, border=None):
@@ -19,18 +20,70 @@ class Style():
19
20
  if border:
20
21
  self.border = border
21
22
 
22
-
23
- class Theme():
23
+ def to_css(self):
24
+ return f"""
25
+ --{self.name}-color: { self.color };
26
+ --{self.name}-border: { self.border };
27
+ --{self.name}-background: { self.background };
28
+ """
29
+
30
+ class ColorSchema:
31
+ def to_css(self):
32
+ css = []
33
+ css.append("<style>")
34
+ css.append(":root{")
35
+ css.append(f"--border-radius: {self.border_radius}px;")
36
+ css.append(self.default.to_css())
37
+ css.append(self.header.to_css())
38
+ css.append(self.footer.to_css())
39
+ css.append(self.fieldset.to_css())
40
+ css.append(self.input.to_css())
41
+ css.append(self.primary.to_css())
42
+ css.append(self.secondary.to_css())
43
+ css.append(self.auxiliary.to_css())
44
+ css.append(self.highlight.to_css())
45
+ css.append(self.info.to_css())
46
+ css.append(self.success.to_css())
47
+ css.append(self.warning.to_css())
48
+ css.append(self.danger.to_css())
49
+ css.append("</style>")
50
+ return "\n".join(css)
51
+
52
+
53
+ class Light(ColorSchema):
24
54
  def __init__(self):
25
- self.primary:Style = Style("#1351b4")
26
- self.secondary:Style = Style("#071e41")
27
- self.auxiliary:Style = Style("#2670e8")
28
- self.highlight:Style = Style("#0c326f")
29
-
30
- self.info:Style = Style("#1351b4", "#d4e5ff")
31
- self.success:Style = Style("#1351b4")
32
- self.warning:Style = Style("#fff5c2")
33
- self.danger:Style = Style("#e52207")
55
+ self.border_radius = 0
56
+ self.default: Style = Style("default", color="#383838", background="#FFFFFF")
57
+ self.header: Style = Style("header", color="#383838", background="#FFFFFF")
58
+ self.footer: Style = Style("footer", color="#383838", background="#FFFFFF")
59
+ self.fieldset: Style = Style("fieldset", color="#383838", background="#FFFFFF")
60
+ self.input: Style = Style("input", border="solid 1px #d9d9d9", background="#FFFFFF")
61
+ self.primary:Style = Style("primary", color="#1351b4", background="#1351b4")
62
+ self.secondary:Style = Style("secondary", color="#071e41")
63
+ self.auxiliary:Style = Style("auxiliary", color="#2670e8", background="#f8f8f8")
64
+ self.highlight:Style = Style("hightlight", color="#0c326f")
65
+ self.info:Style = Style("info", color="#1351b4", background="#d4e5ff")
66
+ self.success:Style = Style("success", color="#ffffff", background="#1351b4")
67
+ self.warning:Style = Style("warning", color="#fff5c2")
68
+ self.danger:Style = Style("danger", color="#e52207")
69
+
70
+
71
+ class Dark(ColorSchema):
72
+ def __init__(self):
73
+ self.border_radius = 3
74
+ self.default: Style = Style("default", color="#c3d0e5", background="#0D1117")
75
+ self.header: Style = Style("header", color="#383838", background="#FFFFFF")
76
+ self.footer: Style = Style("footer", color="#383838", background="#FFFFFF")
77
+ self.fieldset: Style = Style("fieldset", color="#91aad2", background="#262c35")
78
+ self.input: Style = Style("input", border="0", background="#0D1117")
79
+ self.primary:Style = Style("primary", color="#c3d0e5", background="#90C4F9")
80
+ self.secondary:Style = Style("secondary", color="#071e41")
81
+ self.auxiliary:Style = Style("auxiliary", color="#91aad2", background="#262c35")
82
+ self.highlight:Style = Style("hightlight", color="#0c326f")
83
+ self.info:Style = Style("info", color="#c3d0e5", background="#262c35")
84
+ self.success:Style = Style("success", color="#c3d0e5", background="#121f1a", border="1px solid #3b622b")
85
+ self.warning:Style = Style("warning", color="#fff5c2")
86
+ self.danger:Style = Style("danger", color="#e52207")
34
87
 
35
88
 
36
89
  class Groups(dict):
@@ -71,8 +124,8 @@ class Menu(dict):
71
124
  return items
72
125
 
73
126
  class Oauth(list):
74
- def add(self, name, client_id, client_secret, redirect_uri, authorize_url, access_token_url, user_data_url, user_logout_url, user_scope, user_create, user_username, user_email):
75
- super().append(dict(name=name, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, authorize_url=authorize_url, access_token_url=access_token_url, user_data_url=user_data_url, user_logout_url=user_logout_url, user_scope=user_scope, user_create=user_create, user_username=user_username, user_email=user_email))
127
+ def add(self, name, client_id, client_secret, redirect_uri, authorize_url, access_token_url, user_data_url, user_username, user_email=None, user_scope=None, user_create=False, user_logout_url=None):
128
+ super().append(dict(name=name, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, authorize_url=authorize_url, access_token_url=access_token_url, user_data_url=user_data_url, user_username=user_username, user_email=user_email, user_scope=user_scope, user_create=user_create, user_logout_url=user_logout_url))
76
129
 
77
130
  def serialize(self):
78
131
  data = []
@@ -96,6 +149,7 @@ class Dashboard():
96
149
  def __init__(self):
97
150
  self.actions:List = List()
98
151
  self.toolbar:List = List()
152
+ self.todo:List = List()
99
153
  self.top:List = List()
100
154
  self.center:List = List()
101
155
  self.boxes:List = List()
@@ -107,6 +161,12 @@ class Dashboard():
107
161
  self.index = "dashboard"
108
162
 
109
163
 
164
+ class Theme:
165
+ def __init__(self):
166
+ self.light = Light()
167
+ self.dark = Dark()
168
+
169
+
110
170
  class ApplicationMetaclass(type):
111
171
 
112
172
  def __new__(mcs, name, bases, attrs):
@@ -124,6 +184,7 @@ class Application(metaclass=ApplicationMetaclass):
124
184
  self.subtitle = "Take your time!"
125
185
  self.icon = "/static/images/logo.png"
126
186
  self.logo = "/static/images/logo.png"
187
+ self.brand = None
127
188
  self.version = "0.0.1"
128
189
  self.oauth:Oauth = Oauth()
129
190
  self.groups:Groups = Groups()
@@ -136,7 +197,8 @@ class Application(metaclass=ApplicationMetaclass):
136
197
 
137
198
  def serialize(self, request):
138
199
  icon = build_url(request, self.icon)
139
- logo = build_url(request, self.logo)
200
+ logo = build_url(request, self.brand or self.logo)
201
+ title = self.title if self.brand is None else None
140
202
  if request.user.is_authenticated:
141
203
  user = request.user.username.split()[0].split("@")[0]
142
204
  profile = apps.get_model("slth", "profile").objects.filter(user=request.user).first()
@@ -158,7 +220,7 @@ class Application(metaclass=ApplicationMetaclass):
158
220
  type="application",
159
221
  icon=icon,
160
222
  navbar=dict(
161
- type="navbar", title=self.title, subtitle=self.subtitle, logo=logo, user=user, **endpoints
223
+ type="navbar", title=title, subtitle=self.subtitle, logo=logo, user=user, **endpoints
162
224
  ),
163
225
  menu=dict(
164
226
  type="menu", items=self.menu.process(request), user=user, image=photo
@@ -13,6 +13,7 @@ class ApiApplication(Application):
13
13
  "pushsubscription.pushsubscriptions",
14
14
  "job.jobs",
15
15
  "deletion.deletions",
16
+ "settings.settings",
16
17
  "auth.logout",
17
18
  )
18
19
  self.dashboard.boxes.add("user.users")
@@ -95,9 +95,9 @@ class Indicators(dict):
95
95
 
96
96
 
97
97
  class Boxes(dict):
98
- def __init__(self, title):
98
+ def __init__(self, title=None):
99
99
  self["type"] = "boxes"
100
- self["title"] = str(title)
100
+ self["title"] = str(title) if title else None
101
101
  self["items"] = []
102
102
 
103
103
  def append(self, icon, label, url, style=None):
@@ -1,13 +1,13 @@
1
1
  import io
2
+ import os
2
3
  import inspect
3
4
  from ..models import Log
4
5
  from django.apps import apps
5
6
  from typing import TypeVar, Generic
6
7
  from django.core.cache import cache
7
- from django.conf import settings
8
8
  from django.utils.text import slugify
9
9
  from django.db import models
10
- from django.http import JsonResponse, HttpResponse
10
+ from django.http import JsonResponse, HttpResponse, StreamingHttpResponse
11
11
  from ..factory import FormFactory
12
12
  from django.core.exceptions import ValidationError
13
13
  from slth import forms
@@ -27,7 +27,7 @@ from ..exceptions import JsonResponseException, ReadyResponseException
27
27
  from ..utils import build_url, append_url
28
28
  from ..models import Log, Job
29
29
  from slth.queryset import QuerySet
30
- from slth import ENDPOINTS
30
+ from slth import ENDPOINTS, dumps
31
31
  from ..threadlocal import tl
32
32
  from ..tasks import Task
33
33
 
@@ -42,7 +42,8 @@ class ApiResponse(JsonResponse):
42
42
  self["Access-Control-Allow-Headers"] = "*"
43
43
  self["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS, PUT, DELETE, PATCH"
44
44
  self["Access-Control-Max-Age"] = "600"
45
- # print(json.dumps(args[0], indent=1, ensure_ascii=False))
45
+ x = args[0]
46
+ #os.system('clear'); print(dumps(args[0]))
46
47
 
47
48
 
48
49
  class EnpointMetaclass(type):
@@ -91,7 +92,8 @@ class Endpoint(metaclass=EnpointMetaclass):
91
92
  return self.formfactory().fields(*fields) if fields else {}
92
93
 
93
94
  def post(self):
94
- return Response(message="Ação realizada com sucesso")
95
+ redirect = '.' if 'only' in self.request.GET else self.form._redirect
96
+ return Response(message="Ação realizada com sucesso", redirect=redirect)
95
97
 
96
98
  def check_permission(self):
97
99
  return self.request.user.is_superuser
@@ -115,6 +117,7 @@ class Endpoint(metaclass=EnpointMetaclass):
115
117
  raise JsonResponseException(dict(type="redirect", url=url, autosubmit=self.request.GET.get('autosubmit')))
116
118
 
117
119
  def render(self, data, template=None, pdf=False, autoreload=None):
120
+ from django.conf import settings
118
121
  base_url=settings.SITE_URL
119
122
  data.update(base_url=base_url)
120
123
  if template is None:
@@ -157,7 +160,8 @@ class Endpoint(metaclass=EnpointMetaclass):
157
160
  else:
158
161
  self.cleaned_data = self.form.submit()
159
162
  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)
163
+ redirect = '.' if 'only' in self.request.GET else self.form._redirect
164
+ return Response(self.form._message, redirect, dispose=self.form._dispose)
161
165
  else:
162
166
  return self.post()
163
167
  except ValidationError as e:
@@ -168,6 +172,8 @@ class Endpoint(metaclass=EnpointMetaclass):
168
172
  data = self.form
169
173
  elif isinstance(data, Form) or isinstance(data, ModelForm):
170
174
  data = data.settitle(title)
175
+ elif isinstance(data, HttpResponse) or isinstance(data, StreamingHttpResponse):
176
+ raise ReadyResponseException(data)
171
177
  elif self.request.method == "POST":# and not data:
172
178
  return self.post()
173
179
  return data
@@ -580,36 +586,36 @@ class Dashboard(Endpoint):
580
586
 
581
587
  def get(self):
582
588
  application = ApplicationConfig.get_instance()
583
- serializer = Serializer(request=self.request)
589
+ serializer = self.serializer()
590
+ if application.dashboard.actions:
591
+ serializer.actions(*application.dashboard.actions)
592
+ if application.dashboard.todo:
593
+ serializer.todo(*application.dashboard.todo)
594
+ if application.dashboard.top:
595
+ group = serializer.group("Top")
596
+ for name in application.dashboard.top:
597
+ cls = ENDPOINTS[name]
598
+ endpoint = cls.instantiate(self.request, self)
599
+ if endpoint.check_permission():
600
+ group.endpoint(cls)
601
+ group.parent()
584
602
  if application.dashboard.boxes:
585
603
  boxes = Boxes("Acesso Rápido")
586
604
  for name in application.dashboard.boxes:
587
605
  cls = ENDPOINTS[name]
588
606
  endpoint = cls().contextualize(self.request)
589
607
  if endpoint.check_permission():
590
- icon = endpoint.get_icon() or "check"
608
+ icon = endpoint.get_icon() or "link"
591
609
  label = endpoint.get_verbose_name()
592
610
  url = build_url(self.request, cls.get_api_url())
593
611
  boxes.append(icon, label, url)
594
- serializer.append("Acesso Rápido", boxes)
595
- if application.dashboard.top:
596
- group = serializer.group("Top")
597
- for name in application.dashboard.top:
598
- cls = ENDPOINTS[name]
599
- endpoint = cls.instantiate(self.request, self)
600
- if endpoint.check_permission():
601
- group.endpoint(
602
- endpoint.get_verbose_name(), cls, wrap=False
603
- )
604
- group.parent()
612
+ serializer.append(boxes)
605
613
  if application.dashboard.center:
606
614
  for name in application.dashboard.center:
607
615
  cls = ENDPOINTS[name]
608
616
  endpoint = cls.instantiate(self.request, self)
609
617
  if endpoint.check_permission():
610
- serializer.endpoint(
611
- endpoint.get_verbose_name(), cls, wrap=False
612
- )
618
+ serializer.endpoint(cls)
613
619
  return serializer
614
620
 
615
621
  def check_permission(self):
@@ -0,0 +1,60 @@
1
+ from slth import endpoints
2
+ from ..models import Settings as SettingsModel
3
+
4
+
5
+ class Settings(endpoints.ListEndpoint[SettingsModel]):
6
+ class Meta:
7
+ modal = False
8
+ verbose_name = 'Configurações'
9
+
10
+ def get(self):
11
+ return (
12
+ super().get()
13
+ .actions('settings.add', 'settings.view', 'settings.edit', 'settings.delete')
14
+ )
15
+
16
+
17
+ class Add(endpoints.AddEndpoint[SettingsModel]):
18
+ class Meta:
19
+ icon = 'plus'
20
+ verbose_name = 'Cadastrar Configuração'
21
+
22
+ def get(self):
23
+ return (
24
+ super().get()
25
+ )
26
+
27
+
28
+ class View(endpoints.ViewEndpoint[SettingsModel]):
29
+ class Meta:
30
+ modal = False
31
+ icon = 'eye'
32
+ verbose_name = 'Visualizar Configuração'
33
+
34
+ def get(self):
35
+ return (
36
+ super().get()
37
+ )
38
+
39
+
40
+ class Edit(endpoints.EditEndpoint[SettingsModel]):
41
+ class Meta:
42
+ icon = 'pen'
43
+ verbose_name = 'Editar Configuração'
44
+
45
+ def get(self):
46
+ return (
47
+ super().get()
48
+ )
49
+
50
+
51
+ class Delete(endpoints.DeleteEndpoint[SettingsModel]):
52
+ class Meta:
53
+ icon = 'trash'
54
+ verbose_name = 'Excluir Configuração'
55
+
56
+ def get(self):
57
+ return (
58
+ super().get()
59
+ )
60
+
@@ -9,7 +9,8 @@ class Users(endpoints.ListEndpoint[User]):
9
9
 
10
10
 
11
11
  class Add(endpoints.AddEndpoint[User]):
12
- pass
12
+ class Meta:
13
+ icon = "user-plus"
13
14
 
14
15
 
15
16
  class View(endpoints.ViewEndpoint[User]):
@@ -17,11 +18,13 @@ class View(endpoints.ViewEndpoint[User]):
17
18
 
18
19
 
19
20
  class Edit(endpoints.EditEndpoint[User]):
20
- pass
21
+ class Meta:
22
+ icon = "user-pen"
21
23
 
22
24
 
23
25
  class Delete(endpoints.DeleteEndpoint[User]):
24
- pass
26
+ class Meta:
27
+ icon = "user-minus"
25
28
 
26
29
 
27
30
  class ChangePassword(endpoints.ChildInstanceEndpoint):
@@ -66,8 +66,15 @@ class FormController:
66
66
  v = v.strftime("%Y-%m-%d")
67
67
  self.controls["set"][k] = v
68
68
 
69
- def get(self, field_name, default=None):
70
- return self.field_value(field_name, self.form.request.GET.get(field_name, default))
69
+ def get(self, field_name, *field_names, default=None):
70
+ value = self.field_value(field_name, self.form.request.GET.get(field_name, default))
71
+ if field_names:
72
+ values = [value]
73
+ for field_name in field_names:
74
+ values.append(self.field_value(field_name, self.form.request.GET.get(field_name, default)))
75
+ return values
76
+ else:
77
+ return value
71
78
 
72
79
  def field_value(self, name, value, default=None):
73
80
  if value is None:
@@ -276,7 +283,7 @@ class FormMixin:
276
283
  max=field.max,
277
284
  name=name,
278
285
  count=len(instances),
279
- label=label,
286
+ label=str(label),
280
287
  required=required,
281
288
  value=value,
282
289
  )
@@ -333,10 +340,10 @@ class FormMixin:
333
340
  data = dict(
334
341
  type=ftype,
335
342
  name=fname,
336
- label=field.label,
343
+ label=str(field.label) if field.label else None,
337
344
  required=field.required,
338
345
  value=value,
339
- help_text=field.help_text,
346
+ help_text=str(field.help_text),
340
347
  mask=None,
341
348
  )
342
349
  data.update(**extra)
@@ -0,0 +1,36 @@
1
+ import os
2
+ import requests
3
+
4
+ """
5
+ from slth.integrations import deepseek
6
+ deepseek.ask("Em uma única palavra, qual a capital do Brasil?")
7
+ """
8
+
9
+ DEEPSEEK_TOKEN = os.environ.get("DEEPSEEK_TOKEN")
10
+
11
+
12
+ def ask(prompt, model="deepseek-chat"):
13
+ headers = {
14
+ "Authorization": "Bearer {}".format(DEEPSEEK_TOKEN),
15
+ "Content-Type": "application/json",
16
+ }
17
+ data = {
18
+ "model": model,
19
+ "messages": [
20
+ {"role": "system", "content": "You are a helpful assistant."},
21
+ {
22
+ "role": "user",
23
+ "content": prompt,
24
+ },
25
+ ],
26
+ "stream": False,
27
+ }
28
+
29
+ response = requests.post(
30
+ "https://api.deepseek.com/chat/completions", headers=headers, json=data
31
+ )
32
+ data = response.json()
33
+ try:
34
+ return data["choices"][0]["message"]["content"]
35
+ except KeyError:
36
+ return Exception(response.text)
@@ -0,0 +1,23 @@
1
+ import os
2
+ import requests
3
+
4
+ """
5
+ from slth.integrations.google import gemini
6
+ gemini.ask("Qual a capital do Brasil?")
7
+ """
8
+
9
+ GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
10
+
11
+ def ask(prompt):
12
+ data = {"contents": [{"parts":[{"text": prompt}]}]}
13
+ response = requests.post(
14
+ "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={}".format(
15
+ GEMINI_API_KEY
16
+ ), json=data
17
+ )
18
+ data = response.json()
19
+ try:
20
+ return data["candidates"][0]["content"]["parts"][0]["text"].strip()
21
+ except KeyError or IndexError:
22
+ return Exception(response.text)
23
+
@@ -0,0 +1,41 @@
1
+ import os
2
+ import requests
3
+
4
+ """
5
+ from slth.integrations.google import places
6
+ places.search("Natal Shopping, Natal, RN")
7
+ places.geolocation("ChIJj2AvPX__sgcRNr1SxD-1jdU")
8
+ """
9
+
10
+ def search(description):
11
+ response = requests.get(
12
+ "https://maps.googleapis.com/maps/api/place/autocomplete/json?input={}&key={}".format(
13
+ description, os.environ['GOOGLE_TOKEN']
14
+ )
15
+ )
16
+ data = response.json()
17
+ try:
18
+ return [dict(id=prediction['place_id'], value=prediction['description']) for prediction in data['predictions']]
19
+ except KeyError:
20
+ return Exception(response.text)
21
+
22
+ def geolocation(id_or_description):
23
+ if ' ' in id_or_description:
24
+ data = search(id_or_description)
25
+ place_id = data[0]['id'] if data else None
26
+ else:
27
+ place_id = id_or_description
28
+
29
+ if place_id:
30
+ response = requests.get(
31
+ "https://maps.googleapis.com/maps/api/place/details/json?place_id={}&key={}".format(
32
+ place_id, os.environ['GOOGLE_TOKEN']
33
+ )
34
+ )
35
+ data = response.json()
36
+ try:
37
+ location = data['result']['geometry']['location']
38
+ return location['lat'], location['lng']
39
+ except KeyError:
40
+ return Exception(response.text)
41
+ return None
@@ -0,0 +1,18 @@
1
+ import os
2
+ import requests
3
+ import base64
4
+
5
+
6
+ def ocr(uri):
7
+ if uri.startswith('http'):
8
+ image = {"source": {"image_uri": uri}}
9
+ else:
10
+ with open(uri, 'rb') as file:
11
+ image = {"content": base64.b64encode(file.read()).decode()}
12
+ url = 'https://vision.googleapis.com/v1/images:annotate?key={}'.format(os.environ['GOOGLE_TOKEN'])
13
+ data = {"requests": [{"image": image, "features": {"type": "TEXT_DETECTION"}}]}
14
+ response = requests.post(url, json=data).json()
15
+ for item in response['responses']:
16
+ if item and 'fullTextAnnotation' in item:
17
+ return item['fullTextAnnotation']['text']
18
+ return None
@@ -0,0 +1,15 @@
1
+ import os
2
+ import requests
3
+
4
+ JUSTVOIP_USERNAME = os.environ.get('JUSTVOIP_USERNAME')
5
+ JUSTVOIP_PASSWORD = os.environ.get('JUSTVOIP_PASSWORD')
6
+ JUSTVOIP_FROM = os.environ.get('JUSTVOIP_FROM')
7
+
8
+
9
+ def send(to, message):
10
+ to = '55{}'.format(to).replace('-', '').replace('(', '').replace(')', '').replace(' ', '')
11
+ url = 'https://www.justvoip.com/myaccount/sendsms.php?username={}&password={}&from={}&to={}&text={}'.format(
12
+ JUSTVOIP_USERNAME, JUSTVOIP_PASSWORD, JUSTVOIP_FROM, to, message
13
+ )
14
+ response = requests.get(url)
15
+ print(response.text)
@@ -0,0 +1,48 @@
1
+
2
+ import os
3
+ import requests
4
+ import uuid
5
+
6
+ """
7
+ from slth.integrations import mercadopago
8
+ id = mercadopago.payment("04770402414", "juca@mail.com", "pix", "Produto 01", 1)
9
+ mercadopago.approved(id)
10
+ """
11
+
12
+ MERCADOPAGO_TOKEN = os.environ.get('MERCADOPAGO_TOKEN')
13
+
14
+ def payment_methods():
15
+ url = 'https://api.mercadopago.com/v1/payment_methods'
16
+ headers = {'Authorization': f'Bearer {MERCADOPAGO_TOKEN}'}
17
+ response = requests.get(url, headers=headers)
18
+ return [dict(id=method['id'], value=method['name']) for method in response.json()]
19
+
20
+ def payment(cpf, email, payment_method, description, amount):
21
+ url = 'https://api.mercadopago.com/v1/payments'
22
+ headers = {'Authorization': f'Bearer {MERCADOPAGO_TOKEN}'}
23
+ data = {
24
+ "description": description,
25
+ "external_reference": cpf,
26
+ "payer": {
27
+ "email": email,
28
+ "identification": {
29
+ "type": "CPF",
30
+ "number": cpf
31
+ }
32
+ },
33
+ "payment_method_id": payment_method,
34
+ "transaction_amount": float(amount)
35
+ }
36
+ response = requests.post(url, headers=headers, json=data)
37
+ data = response.json()
38
+ try:
39
+ return data['id']
40
+ except KeyError:
41
+ raise Exception(response.text)
42
+
43
+ def approved(id):
44
+ url = f'https://api.mercadopago.com/v1/payments/{id}'
45
+ headers = {'Authorization': f'Bearer {MERCADOPAGO_TOKEN}'}
46
+ response = requests.get(url, headers=headers)
47
+ data = response.json()
48
+ return data['status'] == "approved"
@@ -0,0 +1,30 @@
1
+ import os
2
+ import requests
3
+
4
+ """
5
+ from slth.integrations.openai import chatgpt
6
+ chatgpt.ask("Qual a capital do Brasil?")
7
+ """
8
+
9
+ OPENAI_TOKEN = os.environ.get('OPENAI_TOKEN')
10
+
11
+ def ask(prompt, model="gpt-4"):
12
+ headers = {
13
+ "Authorization": "Bearer {}".format(OPENAI_TOKEN),
14
+ "Content-Type": "application/json"
15
+ }
16
+ data = {
17
+ "model": model, # Or "gpt-3.5-turbo"
18
+ "messages": [
19
+ {"role": "system", "content": "You are a helpful assistant."},
20
+ {"role": "user", "content": prompt}
21
+ ],
22
+ "temperature": 0.7
23
+ }
24
+
25
+ response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=data)
26
+ data = response.json()
27
+ try:
28
+ return data['choices'][0]['message']['content']
29
+ except KeyError:
30
+ return Exception(response.text)