Compare commits
4 Commits
8732785426
...
de9e0f488a
Author | SHA1 | Date |
---|---|---|
Ales (Shagi) Zabala Alava | de9e0f488a | |
Ales (Shagi) Zabala Alava | f881ada65c | |
Ales (Shagi) Zabala Alava | d62b8ab252 | |
Ales (Shagi) Zabala Alava | b0eaa66e37 |
|
@ -19,14 +19,14 @@ class GASLoginView(LoginView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
css = gas_settings.MEDIA['css']
|
css = gas_settings.MEDIA['css']
|
||||||
js = gas_settings.MEDIA['js']
|
javascript = gas_settings.MEDIA['js']
|
||||||
if gas_settings.EXTRA_MEDIA:
|
if gas_settings.EXTRA_MEDIA:
|
||||||
css = css + gas_settings.EXTRA_MEDIA.get('css', [])
|
css = css + gas_settings.EXTRA_MEDIA.get('css', [])
|
||||||
js = js + gas_settings.EXTRA_MEDIA.get('js', [])
|
javascript = javascript + gas_settings.EXTRA_MEDIA.get('js', [])
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'logo_static_url': gas_settings.LOGO,
|
'logo_static_url': gas_settings.LOGO,
|
||||||
'css': css,
|
'css': css,
|
||||||
'js': js,
|
'js': javascript,
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ urlpatterns = [
|
||||||
path('', views.UserList.as_view(), name="user_list"),
|
path('', views.UserList.as_view(), name="user_list"),
|
||||||
path('create/', views.CreateUser.as_view(), name="user_create"),
|
path('create/', views.CreateUser.as_view(), name="user_create"),
|
||||||
path('<int:pk>/edit/', views.UpdateUser.as_view(), name="user_update"),
|
path('<int:pk>/edit/', views.UpdateUser.as_view(), name="user_update"),
|
||||||
path('<int:pk>/change-password/', views.ChangePasswordUser.as_view(), name="user_change_password"),
|
path(
|
||||||
|
'<int:pk>/change-password/',
|
||||||
|
views.ChangePasswordUser.as_view(),
|
||||||
|
name="user_change_password"),
|
||||||
path('<int:pk>/delete/', views.DeleteUser.as_view(), name="user_delete"),
|
path('<int:pk>/delete/', views.DeleteUser.as_view(), name="user_delete"),
|
||||||
]
|
]
|
||||||
|
|
14
gas/sites.py
14
gas/sites.py
|
@ -10,7 +10,7 @@ class Entry:
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.url = url
|
self.url = url
|
||||||
self.roles = roles
|
self.roles = roles
|
||||||
self.children = dict()
|
self.children = {}
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.order = order if order is not None else float("inf")
|
self.order = order if order is not None else float("inf")
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class Entry:
|
||||||
return super().__lt__(other)
|
return super().__lt__(other)
|
||||||
|
|
||||||
|
|
||||||
class GASSite(object):
|
class GASSite:
|
||||||
base_role = 'admins'
|
base_role = 'admins'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -42,12 +42,12 @@ class GASSite(object):
|
||||||
exposed when gas is not active.
|
exposed when gas is not active.
|
||||||
"""
|
"""
|
||||||
if prefix in self._registry['urls']:
|
if prefix in self._registry['urls']:
|
||||||
raise ImproperlyConfigured("Prefix {0} already in use".format(prefix))
|
raise ImproperlyConfigured(f"Prefix {prefix} already in use")
|
||||||
self._registry['urls'][prefix] = urls
|
self._registry['urls'][prefix] = urls
|
||||||
|
|
||||||
def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None, order=None):
|
def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None, order=None):
|
||||||
if name in self._registry['menu']:
|
if name in self._registry['menu']:
|
||||||
raise ImproperlyConfigured("Menu entry '{0}' already registered.".format(name))
|
raise ImproperlyConfigured(f"Menu entry '{name}' already registered.")
|
||||||
|
|
||||||
if roles is None:
|
if roles is None:
|
||||||
roles = set()
|
roles = set()
|
||||||
|
@ -61,8 +61,8 @@ class GASSite(object):
|
||||||
if parent:
|
if parent:
|
||||||
try:
|
try:
|
||||||
parent_entry = self._registry['menu'][parent]
|
parent_entry = self._registry['menu'][parent]
|
||||||
except KeyError:
|
except KeyError as exc:
|
||||||
raise ImproperlyConfigured("Parent {} not registered.".format(parent))
|
raise ImproperlyConfigured("Parent {parent} not registered.") from exc
|
||||||
parent_entry.children[name] = entry
|
parent_entry.children[name] = entry
|
||||||
|
|
||||||
self._registry['menu'][name] = entry
|
self._registry['menu'][name] = entry
|
||||||
|
@ -86,7 +86,7 @@ class GASSite(object):
|
||||||
for prefix, urls in self._registry['urls'].items():
|
for prefix, urls in self._registry['urls'].items():
|
||||||
if prefix:
|
if prefix:
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
re_path(r'^{0}/'.format(prefix), include(urls)),
|
re_path(r'^{prefix}/', include(urls)),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
|
|
20
gas/utils.py
20
gas/utils.py
|
@ -6,13 +6,13 @@ from django.utils.functional import Promise
|
||||||
|
|
||||||
|
|
||||||
class JSONEncoder(json.JSONEncoder):
|
class JSONEncoder(json.JSONEncoder):
|
||||||
def default(self, obj):
|
def default(self, o):
|
||||||
if isinstance(obj, datetime.datetime):
|
if isinstance(o, datetime.datetime):
|
||||||
return obj.strftime('%Y-%m-%d %H:%M')
|
return o.strftime('%Y-%m-%d %H:%M')
|
||||||
if isinstance(obj, datetime.date):
|
if isinstance(o, datetime.date):
|
||||||
return obj.strftime('%Y-%m-%d')
|
return o.strftime('%Y-%m-%d')
|
||||||
if isinstance(obj, QuerySet):
|
if isinstance(o, QuerySet):
|
||||||
return list(obj)
|
return list(o)
|
||||||
if isinstance(obj, Promise):
|
if isinstance(o, Promise):
|
||||||
return str(obj)
|
return str(o)
|
||||||
return json.JSONEncoder.default(self, obj)
|
return json.JSONEncoder.default(self, o)
|
||||||
|
|
78
gas/views.py
78
gas/views.py
|
@ -1,11 +1,10 @@
|
||||||
import json
|
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.admin.utils import NestedObjects
|
from django.contrib.admin.utils import NestedObjects
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import router
|
from django.db import router
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest, JsonResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.cache import add_never_cache_headers
|
||||||
from django.utils.html import escape, escapejs
|
from django.utils.html import escape, escapejs
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -44,30 +43,26 @@ class AjaxCommandsMixin:
|
||||||
"""
|
"""
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
if 'command' in self.request.POST:
|
if 'command' in self.request.POST:
|
||||||
command_processor = getattr(self, 'do_{0}'.format(self.request.POST['command']), None)
|
command = self.request.POST['command']
|
||||||
|
command_processor = getattr(self, f'do_{command}', None)
|
||||||
if command_processor is not None:
|
if command_processor is not None:
|
||||||
return command_processor()
|
return command_processor()
|
||||||
else:
|
return HttpResponseBadRequest()
|
||||||
return HttpResponseBadRequest()
|
handler = getattr(super(), 'post', self.http_method_not_allowed)
|
||||||
else:
|
return handler(request, *args, **kwargs)
|
||||||
handler = getattr(super(), 'post', self.http_method_not_allowed)
|
|
||||||
return handler(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
if 'command' in self.request.GET:
|
if 'command' in self.request.GET:
|
||||||
command_processor = getattr(self, 'send_{0}'.format(self.request.GET['command']), None)
|
command = self.request.POST['command']
|
||||||
|
command_processor = getattr(self, f'send_{command}', None)
|
||||||
if command_processor is not None:
|
if command_processor is not None:
|
||||||
return command_processor()
|
return command_processor()
|
||||||
else:
|
return HttpResponseBadRequest()
|
||||||
return HttpResponseBadRequest()
|
handler = getattr(super(), 'get', self.http_method_not_allowed)
|
||||||
else:
|
return handler(request, *args, **kwargs)
|
||||||
handler = getattr(super(), 'get', self.http_method_not_allowed)
|
|
||||||
return handler(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def render_json(self, data, encoder=utils.JSONEncoder):
|
def render_json(self, data, encoder=utils.JSONEncoder):
|
||||||
return HttpResponse(
|
return JsonResponse(data, json_dumps_params={"indent": 2}, encoder=encoder)
|
||||||
json.dumps(data, indent=2, cls=encoder),
|
|
||||||
content_type='application/json')
|
|
||||||
|
|
||||||
|
|
||||||
class GASMixin:
|
class GASMixin:
|
||||||
|
@ -97,7 +92,10 @@ class GASMixin:
|
||||||
|
|
||||||
def dispatch(self, *args, **kwargs):
|
def dispatch(self, *args, **kwargs):
|
||||||
if self.check_user_forbidden():
|
if self.check_user_forbidden():
|
||||||
return HttpResponseRedirect(reverse('gas:login') + '?next={}'.format(self.request.path))
|
path = self.request.path
|
||||||
|
response = HttpResponseRedirect(reverse('gas:login') + f'?next={path}')
|
||||||
|
add_never_cache_headers(response)
|
||||||
|
return response
|
||||||
return super().dispatch(*args, **kwargs)
|
return super().dispatch(*args, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -119,16 +117,14 @@ class GASMixin:
|
||||||
# Forcing possible reverse_lazy evaluation
|
# Forcing possible reverse_lazy evaluation
|
||||||
url = str(self.cancel_url)
|
url = str(self.cancel_url)
|
||||||
return url
|
return url
|
||||||
else:
|
return self.get_success_url()
|
||||||
return self.get_success_url()
|
|
||||||
|
|
||||||
def get_continue_url(self):
|
def get_continue_url(self):
|
||||||
if self.continue_url:
|
if self.continue_url:
|
||||||
# Forcing possible reverse_lazy evaluation
|
# Forcing possible reverse_lazy evaluation
|
||||||
url = str(self.continue_url)
|
url = str(self.continue_url)
|
||||||
return url
|
return url
|
||||||
else:
|
raise ImproperlyConfigured("No URL to redirect to. Provide a continue_url.")
|
||||||
raise ImproperlyConfigured("No URL to redirect to. Provide a continue_url.")
|
|
||||||
|
|
||||||
def get_header_title(self):
|
def get_header_title(self):
|
||||||
" Contents for the <title> tag. "
|
" Contents for the <title> tag. "
|
||||||
|
@ -152,10 +148,10 @@ class GASMixin:
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
css = gas_settings.MEDIA['css']
|
css = gas_settings.MEDIA['css']
|
||||||
js = gas_settings.MEDIA['js']
|
javascript = gas_settings.MEDIA['js']
|
||||||
if gas_settings.EXTRA_MEDIA:
|
if gas_settings.EXTRA_MEDIA:
|
||||||
css = css + gas_settings.EXTRA_MEDIA.get('css', [])
|
css = css + gas_settings.EXTRA_MEDIA.get('css', [])
|
||||||
js = js + gas_settings.EXTRA_MEDIA.get('js', [])
|
javascript = javascript + gas_settings.EXTRA_MEDIA.get('js', [])
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'base_template': self.base_template,
|
'base_template': self.base_template,
|
||||||
'home_url': self.get_home_url(),
|
'home_url': self.get_home_url(),
|
||||||
|
@ -167,7 +163,7 @@ class GASMixin:
|
||||||
'gas_title': gas_settings.TITLE,
|
'gas_title': gas_settings.TITLE,
|
||||||
'logo_static_url': gas_settings.LOGO,
|
'logo_static_url': gas_settings.LOGO,
|
||||||
'css': css,
|
'css': css,
|
||||||
'js': js,
|
'js': javascript,
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
@ -186,8 +182,7 @@ class GASListView(GASMixin, ListView):
|
||||||
self.filter_form = self.get_filter_form()
|
self.filter_form = self.get_filter_form()
|
||||||
if self.filter_form is not None and self.filter_form.is_valid():
|
if self.filter_form is not None and self.filter_form.is_valid():
|
||||||
return self.filter_form.filter(qs)
|
return self.filter_form.filter(qs)
|
||||||
else:
|
return qs
|
||||||
return qs
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
|
@ -216,13 +211,16 @@ class GASCreateView(GASMixin, CreateView):
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
response = super().form_valid(form)
|
response = super().form_valid(form)
|
||||||
if '_popup' in self.request.POST:
|
if '_popup' in self.request.POST:
|
||||||
|
# escape() calls force_text.
|
||||||
|
obj_pk = escape(self.object.pk)
|
||||||
|
obj = escapejs(self.object)
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
'<!DOCTYPE html><html><head><title></title></head><body>'
|
'<!DOCTYPE html><html><head><title></title></head><body>'
|
||||||
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' %
|
'<script type="text/javascript">'
|
||||||
# escape() calls force_text.
|
f' opener.dismissAddAnotherPopup(window, "{obj_pk}", "{obj}");'
|
||||||
(escape(self.object.pk), escapejs(self.object)))
|
'</script></body></html>'
|
||||||
else:
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class GASUpdateView(GASMixin, UpdateView):
|
class GASUpdateView(GASMixin, UpdateView):
|
||||||
|
@ -255,10 +253,14 @@ class GASDeleteView(GASMixin, DeleteView):
|
||||||
|
|
||||||
def format_callback(obj):
|
def format_callback(obj):
|
||||||
opts = obj._meta
|
opts = obj._meta
|
||||||
return '%s: %s' % (capfirst(opts.verbose_name), obj)
|
name = capfirst(opts.verbose_name)
|
||||||
|
return f'{name}: {obj}'
|
||||||
|
|
||||||
collector.collect([self.object])
|
collector.collect([self.object])
|
||||||
model_count = {model._meta.verbose_name_plural: len(objs) for model, objs in collector.model_objs.items()}
|
model_count = {
|
||||||
|
model._meta.verbose_name_plural: len(objs)
|
||||||
|
for model, objs in collector.model_objs.items()
|
||||||
|
}
|
||||||
return collector.nested(format_callback), model_count
|
return collector.nested(format_callback), model_count
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -278,7 +280,7 @@ class GASDeleteView(GASMixin, DeleteView):
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def form_valid(self, form):
|
||||||
response = super().delete(request, *args, **kwargs)
|
response = super().form_valid(form)
|
||||||
messages.add_message(request, messages.SUCCESS, self.get_deleted_text())
|
messages.add_message(self.request, messages.SUCCESS, self.get_deleted_text())
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Django==3.2.13
|
Django>=3.2.13,<5.0
|
||||||
|
|
Loading…
Reference in New Issue