slthcore 0.4.7__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.
- {slthcore-0.4.7/slthcore.egg-info → slthcore-0.4.9}/PKG-INFO +1 -1
- {slthcore-0.4.7 → slthcore-0.4.9}/setup.py +1 -2
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/__init__.py +9 -14
- slthcore-0.4.9/slth/application.py +178 -0
- slthcore-0.4.9/slth/cmd/init/boilerplate/backend/api/__init__.py +27 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/db/models.py +1 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/__init__.py +66 -103
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/factory.py +5 -5
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/forms.py +68 -44
- slthcore-0.4.9/slth/management/commands/api.py +90 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/models.py +7 -4
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/notifications.py +3 -2
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/oauth.py +5 -4
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/queryset.py +7 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/serializer.py +7 -3
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/.DS_Store +0 -0
- slthcore-0.4.9/slth/static/js/slth.min.js +251 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/templates/index.html +9 -9
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/utils.py +8 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/views.py +7 -6
- {slthcore-0.4.7 → slthcore-0.4.9/slthcore.egg-info}/PKG-INFO +1 -1
- {slthcore-0.4.7 → slthcore-0.4.9}/slthcore.egg-info/SOURCES.txt +2 -1
- slthcore-0.4.7/slth/cmd/init/boilerplate/backend/application.yml +0 -64
- slthcore-0.4.7/slth/migrations/__init__.py +0 -0
- slthcore-0.4.7/slth/static/js/slth.min.js +0 -240
- {slthcore-0.4.7 → slthcore-0.4.9}/MANIFEST.in +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/setup.cfg +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/apps.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/configure/__main__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/__main__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/__pycache__/__main__.cpython-312.pyc +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/.DS_Store +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/.gitignore +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/endpoints/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/base.env +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/docker-compose.yml +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/local.env +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/run.sh +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/cmd/init/boilerplate/test.sh +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/components.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/db/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/db/generic.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/auth.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/deletion.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/dev.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/email.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/job.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/log.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/profile.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/pushsubscription.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/report.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/role.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/task.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/timezone.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/user.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/endpoints/whatsappnotification.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/exceptions.py +0 -0
- {slthcore-0.4.7/slth/cmd/init/boilerplate/backend/api → slthcore-0.4.9/slth/management}/__init__.py +0 -0
- {slthcore-0.4.7/slth/management → slthcore-0.4.9/slth/management/commands}/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/management/commands/integration_test.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/management/commands/sync.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/management/commands/worker.py +0 -0
- {slthcore-0.4.7/slth/management/commands → slthcore-0.4.9/slth/middleware}/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/middleware/timezone.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0001_initial.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0004_alter_profile_photo.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0005_alter_profile_photo.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0006_user.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0007_deletion_log.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0008_alter_deletion_datetime_alter_log_datetime.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0009_remove_email_from_email_email_action_email_attempt_and_more.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0010_email_key_alter_email_action_alter_email_attempt_and_more.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0011_usertimezone.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0012_timezone_remove_usertimezone_key_and_more.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/migrations/0013_whatsappnotification.py +0 -0
- {slthcore-0.4.7/slth/middleware → slthcore-0.4.9/slth/migrations}/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/pdf/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/pdf/tests.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/permissions.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/printer.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/roles.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/selenium/__init__.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/selenium/browser.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/css/.DS_Store +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/css/slth.css +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/images/placeholder.png +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/js/index.min.js +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/static/js/react.min.js +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/statistics.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/tasks.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/templates/email.html +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/templates/report.html +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/templates/service-worker.js +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/templates/signature.html +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/tests.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/threadlocal.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/tz.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slth/urls.py +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slthcore.egg-info/dependency_links.txt +0 -0
- {slthcore-0.4.7 → slthcore-0.4.9}/slthcore.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import os
|
|
3
|
-
import yaml
|
|
4
1
|
import json
|
|
5
2
|
import warnings
|
|
6
3
|
from pathlib import Path
|
|
@@ -15,6 +12,7 @@ import django.db.models.options as options
|
|
|
15
12
|
from django.db.models.base import ModelBase
|
|
16
13
|
from django.db.models import Model
|
|
17
14
|
from django.core.exceptions import FieldDoesNotExist
|
|
15
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
18
16
|
from django.utils.autoreload import autoreload_started
|
|
19
17
|
from django.core import serializers
|
|
20
18
|
from django.utils import autoreload
|
|
@@ -29,15 +27,6 @@ FILENAME = 'application.yml'
|
|
|
29
27
|
ENDPOINTS = {}
|
|
30
28
|
PROXIED_MODELS = []
|
|
31
29
|
THREADS = []
|
|
32
|
-
APPLICATON = None
|
|
33
|
-
|
|
34
|
-
if APPLICATON is None and os.path.exists(FILENAME):
|
|
35
|
-
with open(FILENAME) as file:
|
|
36
|
-
content = file.read()
|
|
37
|
-
for variable in re.findall(r'\$[a-zA-z0-9_]+', content):
|
|
38
|
-
content = content.replace(variable, os.environ.get(variable[1:], ''))
|
|
39
|
-
APPLICATON = yaml.safe_load(content).get('application')
|
|
40
|
-
|
|
41
30
|
|
|
42
31
|
class JSONEncoder(json.JSONEncoder):
|
|
43
32
|
def default(self, obj):
|
|
@@ -185,13 +174,19 @@ def save_decorator(func):
|
|
|
185
174
|
if obj:
|
|
186
175
|
for field in self._meta.fields:
|
|
187
176
|
a = getattr(obj, field.name)
|
|
188
|
-
|
|
177
|
+
try:
|
|
178
|
+
b = getattr(self, field.name)
|
|
179
|
+
except ObjectDoesNotExist:
|
|
180
|
+
b = None
|
|
189
181
|
if a != b:
|
|
190
182
|
diff[field.verbose_name] = (serialize(a), serialize(b))
|
|
191
183
|
else:
|
|
192
184
|
action = 'add'
|
|
193
185
|
for field in self._meta.fields:
|
|
194
|
-
|
|
186
|
+
try:
|
|
187
|
+
b = getattr(self, field.name)
|
|
188
|
+
except ObjectDoesNotExist:
|
|
189
|
+
b = None
|
|
195
190
|
if b is not None:
|
|
196
191
|
diff[field.verbose_name] = (None, serialize(b))
|
|
197
192
|
func(self, *args, **kwargs)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
|
|
2
|
+
from slth import ENDPOINTS
|
|
3
|
+
from .utils import build_url
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.apps import apps
|
|
6
|
+
|
|
7
|
+
APPLICATION_CLASS = None
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Style():
|
|
11
|
+
def __init__(self, color="black", background="inherite", border="none"):
|
|
12
|
+
self.update(color=color, background=background, border=border)
|
|
13
|
+
|
|
14
|
+
def update(self, color=None, background=None, border=None):
|
|
15
|
+
if color:
|
|
16
|
+
self.color = color
|
|
17
|
+
if background:
|
|
18
|
+
self.background = background
|
|
19
|
+
if border:
|
|
20
|
+
self.border = border
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Theme():
|
|
24
|
+
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")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Groups(dict):
|
|
37
|
+
def add(self, **kwargs):
|
|
38
|
+
self.update(**kwargs)
|
|
39
|
+
|
|
40
|
+
class Menu(dict):
|
|
41
|
+
def add(self, arg):
|
|
42
|
+
self.update(arg)
|
|
43
|
+
|
|
44
|
+
def process(self, request):
|
|
45
|
+
items = []
|
|
46
|
+
|
|
47
|
+
def get_item(k, v):
|
|
48
|
+
if isinstance(v, dict):
|
|
49
|
+
icon, label = k.split(":") if ":" in k else (None, k)
|
|
50
|
+
subitems = []
|
|
51
|
+
for k1, v1 in v.items():
|
|
52
|
+
subitem = get_item(k1, v1)
|
|
53
|
+
if subitem:
|
|
54
|
+
subitems.append(subitem)
|
|
55
|
+
if subitems:
|
|
56
|
+
return dict(dict(icon=icon, label=label, items=subitems))
|
|
57
|
+
else:
|
|
58
|
+
cls = ENDPOINTS.get(v)
|
|
59
|
+
if cls:
|
|
60
|
+
endpoint = cls().instantiate(request, None)
|
|
61
|
+
if endpoint.check_permission() and endpoint.contribute("menu"):
|
|
62
|
+
icon, label = k.split(":") if ":" in k else (None, k)
|
|
63
|
+
url = build_url(request, cls.get_api_url())
|
|
64
|
+
return dict(dict(label=label, url=url, icon=icon))
|
|
65
|
+
|
|
66
|
+
for k, v in self.items():
|
|
67
|
+
item = get_item(k, v)
|
|
68
|
+
if item:
|
|
69
|
+
items.append(item)
|
|
70
|
+
|
|
71
|
+
return items
|
|
72
|
+
|
|
73
|
+
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))
|
|
76
|
+
|
|
77
|
+
def serialize(self):
|
|
78
|
+
data = []
|
|
79
|
+
for provider in self:
|
|
80
|
+
redirect_uri = "{}{}".format(settings.SITE_URL, provider['redirect_uri'])
|
|
81
|
+
authorize_url = '{}?response_type=code&client_id={}&redirect_uri={}'.format(
|
|
82
|
+
provider['authorize_url'], provider['client_id'], redirect_uri
|
|
83
|
+
)
|
|
84
|
+
if provider.get('scope'):
|
|
85
|
+
authorize_url = '{}&scope={}'.format(authorize_url, provider.get('scope'))
|
|
86
|
+
data.append(dict(label=f'Entrar com {provider["name"]}', url=authorize_url))
|
|
87
|
+
return data
|
|
88
|
+
|
|
89
|
+
class List(list):
|
|
90
|
+
|
|
91
|
+
def add(self, *names):
|
|
92
|
+
super().extend(names)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Dashboard():
|
|
96
|
+
def __init__(self):
|
|
97
|
+
self.actions:List = List()
|
|
98
|
+
self.toolbar:List = List()
|
|
99
|
+
self.top:List = List()
|
|
100
|
+
self.center:List = List()
|
|
101
|
+
self.boxes:List = List()
|
|
102
|
+
self.search:List = List()
|
|
103
|
+
self.usermenu:List = List()
|
|
104
|
+
self.adder:List = List()
|
|
105
|
+
self.tools:List = List()
|
|
106
|
+
self.settings:List = List()
|
|
107
|
+
self.index = "dashboard"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class ApplicationMetaclass(type):
|
|
111
|
+
|
|
112
|
+
def __new__(mcs, name, bases, attrs):
|
|
113
|
+
global APPLICATION_CLASS
|
|
114
|
+
cls = super().__new__(mcs, name, bases, attrs)
|
|
115
|
+
APPLICATION_CLASS = cls
|
|
116
|
+
return cls
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Application(metaclass=ApplicationMetaclass):
|
|
120
|
+
|
|
121
|
+
def __init__(self):
|
|
122
|
+
self.lang = "pt-br"
|
|
123
|
+
self.title = "Sloth"
|
|
124
|
+
self.subtitle = "Take your time!"
|
|
125
|
+
self.icon = "/static/images/logo.png"
|
|
126
|
+
self.logo = "/static/images/logo.png"
|
|
127
|
+
self.version = "0.0.1"
|
|
128
|
+
self.oauth:Oauth = Oauth()
|
|
129
|
+
self.groups:Groups = Groups()
|
|
130
|
+
self.menu:Menu = Menu()
|
|
131
|
+
self.dashboard = Dashboard()
|
|
132
|
+
self.theme:Theme = Theme()
|
|
133
|
+
|
|
134
|
+
def load(self):
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
def serialize(self, request):
|
|
138
|
+
icon = build_url(request, self.icon)
|
|
139
|
+
logo = build_url(request, self.logo)
|
|
140
|
+
if request.user.is_authenticated:
|
|
141
|
+
user = request.user.username.split()[0].split("@")[0]
|
|
142
|
+
profile = apps.get_model("slth", "profile").objects.filter(user=request.user).first()
|
|
143
|
+
photo = profile and profile.photo and build_url(request, profile.photo.url) or None
|
|
144
|
+
else:
|
|
145
|
+
user = profile = photo = None
|
|
146
|
+
endpoints = {"actions": [], "usermenu": [], "adder": [], "settings": [], "tools": [], "toolbar": []}
|
|
147
|
+
for entrypoint in endpoints:
|
|
148
|
+
for endpoint_name in getattr(self.dashboard, entrypoint):
|
|
149
|
+
cls = ENDPOINTS[endpoint_name]
|
|
150
|
+
endpoint = cls().instantiate(request, None)
|
|
151
|
+
if endpoint.check_permission() and endpoint.contribute(entrypoint):
|
|
152
|
+
name = endpoint.get_verbose_name()
|
|
153
|
+
url = build_url(request, cls.get_api_url())
|
|
154
|
+
modal = cls.get_metadata("modal", False)
|
|
155
|
+
icon = cls.get_metadata("icon", None)
|
|
156
|
+
endpoints[entrypoint].append(dict(name=name, url=url, modal=modal, icon=icon))
|
|
157
|
+
return dict(
|
|
158
|
+
type="application",
|
|
159
|
+
icon=icon,
|
|
160
|
+
navbar=dict(
|
|
161
|
+
type="navbar", title=self.title, subtitle=self.subtitle, logo=logo, user=user, **endpoints
|
|
162
|
+
),
|
|
163
|
+
menu=dict(
|
|
164
|
+
type="menu", items=self.menu.process(request), user=user, image=photo
|
|
165
|
+
),
|
|
166
|
+
footer=dict(
|
|
167
|
+
type="footer", version=self.version
|
|
168
|
+
),
|
|
169
|
+
oauth=self.oauth.serialize(),
|
|
170
|
+
sponsors=[]
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
@staticmethod
|
|
174
|
+
def get_instance():
|
|
175
|
+
instance = APPLICATION_CLASS()
|
|
176
|
+
instance.load()
|
|
177
|
+
return instance
|
|
178
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from slth.application import Application
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ApiApplication(Application):
|
|
5
|
+
def __init__(self):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.groups.add(administrador="Administrador", operador="Operador")
|
|
8
|
+
self.dashboard.usermenu.add(
|
|
9
|
+
"dev.icons",
|
|
10
|
+
"user.users",
|
|
11
|
+
"log.logs",
|
|
12
|
+
"email.emails",
|
|
13
|
+
"pushsubscription.pushsubscriptions",
|
|
14
|
+
"job.jobs",
|
|
15
|
+
"deletion.deletions",
|
|
16
|
+
"auth.logout",
|
|
17
|
+
)
|
|
18
|
+
self.dashboard.boxes.add("user.users")
|
|
19
|
+
self.dashboard.actions.add()
|
|
20
|
+
self.dashboard.toolbar.add()
|
|
21
|
+
self.dashboard.top.add()
|
|
22
|
+
self.dashboard.center.add()
|
|
23
|
+
self.dashboard.search.add()
|
|
24
|
+
self.dashboard.adder.add()
|
|
25
|
+
self.dashboard.tools.add()
|
|
26
|
+
self.dashboard.settings.add()
|
|
27
|
+
self.menu.add({"Sair": "auth.logout"})
|
|
@@ -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
|
|
@@ -19,20 +18,16 @@ from django.template.loader import render_to_string
|
|
|
19
18
|
from ..forms import ModelForm, Form
|
|
20
19
|
from ..serializer import serialize, Serializer
|
|
21
20
|
from ..components import (
|
|
22
|
-
Application as Application_,
|
|
23
|
-
Navbar,
|
|
24
|
-
Menu,
|
|
25
|
-
Footer,
|
|
26
21
|
Response,
|
|
27
22
|
Boxes,
|
|
28
23
|
TemplateContent,
|
|
29
24
|
)
|
|
25
|
+
from slth.application import Application as ApplicationConfig
|
|
30
26
|
from ..exceptions import JsonResponseException, ReadyResponseException
|
|
31
27
|
from ..utils import build_url, append_url
|
|
32
|
-
from ..models import
|
|
28
|
+
from ..models import Log, Job
|
|
33
29
|
from slth.queryset import QuerySet
|
|
34
|
-
from slth import
|
|
35
|
-
from .. import oauth
|
|
30
|
+
from slth import ENDPOINTS
|
|
36
31
|
from ..threadlocal import tl
|
|
37
32
|
from ..tasks import Task
|
|
38
33
|
|
|
@@ -68,6 +63,7 @@ class Endpoint(metaclass=EnpointMetaclass):
|
|
|
68
63
|
cache = cache
|
|
69
64
|
|
|
70
65
|
def __init__(self):
|
|
66
|
+
self.form: Form | ModelForm = None
|
|
71
67
|
self.base_url = None
|
|
72
68
|
self.request = None
|
|
73
69
|
self.source = None
|
|
@@ -153,15 +149,15 @@ class Endpoint(metaclass=EnpointMetaclass):
|
|
|
153
149
|
elif isinstance(data, Serializer):
|
|
154
150
|
data = data.contextualize(self.request).settitle(title)
|
|
155
151
|
elif isinstance(data, FormFactory):
|
|
156
|
-
form = self.getform(data.settitle(title).
|
|
157
|
-
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):
|
|
158
154
|
try:
|
|
159
155
|
if isinstance(self, DeleteEndpoint):
|
|
160
156
|
return self.post()
|
|
161
157
|
else:
|
|
162
|
-
self.cleaned_data = form.submit()
|
|
163
|
-
if form._message or form._redirect or form._dispose:
|
|
164
|
-
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)
|
|
165
161
|
else:
|
|
166
162
|
return self.post()
|
|
167
163
|
except ValidationError as e:
|
|
@@ -169,7 +165,7 @@ class Endpoint(metaclass=EnpointMetaclass):
|
|
|
169
165
|
dict(type="error", text="\n".join(e.messages), errors={})
|
|
170
166
|
)
|
|
171
167
|
else:
|
|
172
|
-
data = form
|
|
168
|
+
data = self.form
|
|
173
169
|
elif isinstance(data, Form) or isinstance(data, ModelForm):
|
|
174
170
|
data = data.settitle(title)
|
|
175
171
|
elif self.request.method == "POST":# and not data:
|
|
@@ -340,7 +336,6 @@ class PublicEndpoint(Endpoint):
|
|
|
340
336
|
return True
|
|
341
337
|
|
|
342
338
|
|
|
343
|
-
|
|
344
339
|
class ModelEndpoint(Endpoint):
|
|
345
340
|
def __init__(self):
|
|
346
341
|
self.model = self.__orig_bases__[0].__args__[0]
|
|
@@ -506,14 +501,52 @@ class ChildInstanceEndpoint(ChildEndpoint):
|
|
|
506
501
|
return Serializer(self.get_instance()).contextualize(self.request)
|
|
507
502
|
|
|
508
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
|
+
|
|
509
541
|
class Search(Endpoint):
|
|
510
542
|
def get(self):
|
|
511
543
|
key = "_options_"
|
|
512
544
|
options = self.cache.get(key, [])
|
|
513
545
|
term = self.request.GET.get("term")
|
|
514
|
-
|
|
546
|
+
application = ApplicationConfig.get_instance()
|
|
547
|
+
if options is None and application.dashboard.search:
|
|
515
548
|
options = []
|
|
516
|
-
for name in
|
|
549
|
+
for name in application.dashboard.search:
|
|
517
550
|
cls = ENDPOINTS[name]
|
|
518
551
|
endpoint = cls.instantiate(self.request, self)
|
|
519
552
|
if endpoint.check_permission():
|
|
@@ -531,13 +564,13 @@ class Search(Endpoint):
|
|
|
531
564
|
return result[0:10]
|
|
532
565
|
|
|
533
566
|
|
|
534
|
-
|
|
535
567
|
class Home(PublicEndpoint):
|
|
536
568
|
class Meta:
|
|
537
569
|
verbose_name = ""
|
|
538
570
|
|
|
539
571
|
def get(self):
|
|
540
|
-
|
|
572
|
+
application = ApplicationConfig.get_instance()
|
|
573
|
+
cls = ENDPOINTS[application.dashboard.index]
|
|
541
574
|
self.redirect(cls.get_api_url())
|
|
542
575
|
|
|
543
576
|
|
|
@@ -546,10 +579,11 @@ class Dashboard(Endpoint):
|
|
|
546
579
|
verbose_name = ""
|
|
547
580
|
|
|
548
581
|
def get(self):
|
|
582
|
+
application = ApplicationConfig.get_instance()
|
|
549
583
|
serializer = Serializer(request=self.request)
|
|
550
|
-
if
|
|
584
|
+
if application.dashboard.boxes:
|
|
551
585
|
boxes = Boxes("Acesso Rápido")
|
|
552
|
-
for name in
|
|
586
|
+
for name in application.dashboard.boxes:
|
|
553
587
|
cls = ENDPOINTS[name]
|
|
554
588
|
endpoint = cls().contextualize(self.request)
|
|
555
589
|
if endpoint.check_permission():
|
|
@@ -558,9 +592,9 @@ class Dashboard(Endpoint):
|
|
|
558
592
|
url = build_url(self.request, cls.get_api_url())
|
|
559
593
|
boxes.append(icon, label, url)
|
|
560
594
|
serializer.append("Acesso Rápido", boxes)
|
|
561
|
-
if
|
|
595
|
+
if application.dashboard.top:
|
|
562
596
|
group = serializer.group("Top")
|
|
563
|
-
for name in
|
|
597
|
+
for name in application.dashboard.top:
|
|
564
598
|
cls = ENDPOINTS[name]
|
|
565
599
|
endpoint = cls.instantiate(self.request, self)
|
|
566
600
|
if endpoint.check_permission():
|
|
@@ -568,8 +602,8 @@ class Dashboard(Endpoint):
|
|
|
568
602
|
endpoint.get_verbose_name(), cls, wrap=False
|
|
569
603
|
)
|
|
570
604
|
group.parent()
|
|
571
|
-
if
|
|
572
|
-
for name in
|
|
605
|
+
if application.dashboard.center:
|
|
606
|
+
for name in application.dashboard.center:
|
|
573
607
|
cls = ENDPOINTS[name]
|
|
574
608
|
endpoint = cls.instantiate(self.request, self)
|
|
575
609
|
if endpoint.check_permission():
|
|
@@ -584,79 +618,7 @@ class Dashboard(Endpoint):
|
|
|
584
618
|
|
|
585
619
|
class Application(PublicEndpoint):
|
|
586
620
|
def get(self):
|
|
587
|
-
|
|
588
|
-
photo = None
|
|
589
|
-
navbar = None
|
|
590
|
-
menu = None
|
|
591
|
-
icon = build_url(self.request, APPLICATON["logo"])
|
|
592
|
-
logo = build_url(self.request, APPLICATON["logo"])
|
|
593
|
-
if self.request.user.is_authenticated:
|
|
594
|
-
user = self.request.user.username.split()[0].split("@")[0]
|
|
595
|
-
profile = Profile.objects.filter(user=self.request.user).first()
|
|
596
|
-
photo = profile and profile.photo and build_url(self.request, profile.photo.url) or None
|
|
597
|
-
|
|
598
|
-
navbar = Navbar(
|
|
599
|
-
title=APPLICATON["title"],
|
|
600
|
-
subtitle=APPLICATON["subtitle"],
|
|
601
|
-
logo=logo,
|
|
602
|
-
user=user,
|
|
603
|
-
photo=photo,
|
|
604
|
-
search=False,
|
|
605
|
-
roles=' | '.join((str(role) for role in self.objects('slth.role').filter(username=self.request.user.username)))
|
|
606
|
-
)
|
|
607
|
-
for entrypoint in ["actions", "usermenu", "adder", "settings", "tools", "toolbar"]:
|
|
608
|
-
if APPLICATON["dashboard"][entrypoint]:
|
|
609
|
-
for endpoint_name in APPLICATON["dashboard"][entrypoint]:
|
|
610
|
-
cls = ENDPOINTS[endpoint_name]
|
|
611
|
-
endpoint = cls().instantiate(self.request, self)
|
|
612
|
-
if endpoint.check_permission() and endpoint.contribute(entrypoint):
|
|
613
|
-
label = endpoint.get_verbose_name()
|
|
614
|
-
url = build_url(self.request, cls.get_api_url())
|
|
615
|
-
modal = cls.get_metadata("modal", False)
|
|
616
|
-
icon = cls.get_metadata("icon", None)
|
|
617
|
-
navbar.add_action(entrypoint, label, url, modal, icon=icon)
|
|
618
|
-
|
|
619
|
-
if APPLICATON["menu"]:
|
|
620
|
-
items = []
|
|
621
|
-
|
|
622
|
-
def get_item(k, v):
|
|
623
|
-
if isinstance(v, dict):
|
|
624
|
-
icon, label = k.split(":") if ":" in k else (None, k)
|
|
625
|
-
subitems = []
|
|
626
|
-
for k1, v1 in v.items():
|
|
627
|
-
subitem = get_item(k1, v1)
|
|
628
|
-
if subitem:
|
|
629
|
-
subitems.append(subitem)
|
|
630
|
-
if subitems:
|
|
631
|
-
return dict(dict(icon=icon, label=label, items=subitems))
|
|
632
|
-
else:
|
|
633
|
-
cls = ENDPOINTS.get(v)
|
|
634
|
-
if cls:
|
|
635
|
-
endpoint = cls().instantiate(self.request, self)
|
|
636
|
-
if endpoint.check_permission() and endpoint.contribute("menu"):
|
|
637
|
-
icon, label = k.split(":") if ":" in k else (None, k)
|
|
638
|
-
url = build_url(self.request, cls.get_api_url())
|
|
639
|
-
return dict(dict(label=label, url=url, icon=icon))
|
|
640
|
-
|
|
641
|
-
for k, v in APPLICATON["menu"].items():
|
|
642
|
-
item = get_item(k, v)
|
|
643
|
-
if item:
|
|
644
|
-
items.append(item)
|
|
645
|
-
profile = (
|
|
646
|
-
Profile.objects.filter(user=self.request.user).first() if user else None
|
|
647
|
-
)
|
|
648
|
-
photo_url = (
|
|
649
|
-
profile.photo.url
|
|
650
|
-
if profile and profile.photo
|
|
651
|
-
else "/static/images/user.svg"
|
|
652
|
-
)
|
|
653
|
-
menu = Menu(items, user=user, image=build_url(self.request, photo_url))
|
|
654
|
-
|
|
655
|
-
footer = Footer(APPLICATON["version"])
|
|
656
|
-
return Application_(
|
|
657
|
-
icon=icon, navbar=navbar, menu=menu, footer=footer, oauth=oauth.providers(),
|
|
658
|
-
sponsors=APPLICATON.get("sponsors", ())
|
|
659
|
-
)
|
|
621
|
+
return ApplicationConfig.get_instance().serialize(self.request)
|
|
660
622
|
|
|
661
623
|
|
|
662
624
|
class Manifest(PublicEndpoint):
|
|
@@ -665,17 +627,18 @@ class Manifest(PublicEndpoint):
|
|
|
665
627
|
verbose_name = "Manifest"
|
|
666
628
|
|
|
667
629
|
def get(self):
|
|
630
|
+
application = ApplicationConfig.get_instance()
|
|
668
631
|
return dict(
|
|
669
632
|
{
|
|
670
|
-
"name":
|
|
671
|
-
"short_name":
|
|
633
|
+
"name": application.title,
|
|
634
|
+
"short_name": application.title,
|
|
672
635
|
"lang": "pt-BR",
|
|
673
636
|
"start_url": build_url(self.request, "/app/home/"),
|
|
674
637
|
"scope": build_url(self.request, "/app/"),
|
|
675
638
|
"display": "standalone",
|
|
676
639
|
"icons": [
|
|
677
640
|
{
|
|
678
|
-
"src": build_url(self.request,
|
|
641
|
+
"src": build_url(self.request, application.icon),
|
|
679
642
|
"sizes": "192x192",
|
|
680
643
|
"type": "image/png",
|
|
681
644
|
}
|
|
@@ -689,5 +652,5 @@ class Manifest(PublicEndpoint):
|
|
|
689
652
|
|
|
690
653
|
class About(PublicEndpoint):
|
|
691
654
|
def get(self):
|
|
692
|
-
|
|
693
|
-
|
|
655
|
+
application = ApplicationConfig.get_instance()
|
|
656
|
+
return dict(version=application.version)
|
|
@@ -3,7 +3,7 @@ from .serializer import Serializer
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class FormFactory:
|
|
6
|
-
def __init__(self, instance,
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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():
|