Compare commits

..

No commits in common. "de9e0f488ae72beb90b3242ef368d9ddcf48060a" and "8732785426279c0f775a7dfa85e6689fdbdbb856" have entirely different histories.

6 changed files with 60 additions and 65 deletions

View File

@ -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']
javascript = gas_settings.MEDIA['js'] js = 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', [])
javascript = javascript + gas_settings.EXTRA_MEDIA.get('js', []) js = js + 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': javascript, 'js': js,
}) })
return ctx return ctx

View File

@ -7,9 +7,6 @@ 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( path('<int:pk>/change-password/', views.ChangePasswordUser.as_view(), name="user_change_password"),
'<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"),
] ]

View File

@ -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 = {} self.children = dict()
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: class GASSite(object):
base_role = 'admins' base_role = 'admins'
def __init__(self): def __init__(self):
@ -42,12 +42,12 @@ class GASSite:
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(f"Prefix {prefix} already in use") raise ImproperlyConfigured("Prefix {0} already in use".format(prefix))
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(f"Menu entry '{name}' already registered.") raise ImproperlyConfigured("Menu entry '{0}' already registered.".format(name))
if roles is None: if roles is None:
roles = set() roles = set()
@ -61,8 +61,8 @@ class GASSite:
if parent: if parent:
try: try:
parent_entry = self._registry['menu'][parent] parent_entry = self._registry['menu'][parent]
except KeyError as exc: except KeyError:
raise ImproperlyConfigured("Parent {parent} not registered.") from exc raise ImproperlyConfigured("Parent {} not registered.".format(parent))
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:
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'^{prefix}/', include(urls)), re_path(r'^{0}/'.format(prefix), include(urls)),
) )
else: else:
urlpatterns.append( urlpatterns.append(

View File

@ -6,13 +6,13 @@ from django.utils.functional import Promise
class JSONEncoder(json.JSONEncoder): class JSONEncoder(json.JSONEncoder):
def default(self, o): def default(self, obj):
if isinstance(o, datetime.datetime): if isinstance(obj, datetime.datetime):
return o.strftime('%Y-%m-%d %H:%M') return obj.strftime('%Y-%m-%d %H:%M')
if isinstance(o, datetime.date): if isinstance(obj, datetime.date):
return o.strftime('%Y-%m-%d') return obj.strftime('%Y-%m-%d')
if isinstance(o, QuerySet): if isinstance(obj, QuerySet):
return list(o) return list(obj)
if isinstance(o, Promise): if isinstance(obj, Promise):
return str(o) return str(obj)
return json.JSONEncoder.default(self, o) return json.JSONEncoder.default(self, obj)

View File

@ -1,10 +1,11 @@
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, JsonResponse from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
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 _
@ -43,26 +44,30 @@ 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 = self.request.POST['command'] command_processor = getattr(self, 'do_{0}'.format(self.request.POST['command']), None)
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()
else:
handler = getattr(super(), 'post', self.http_method_not_allowed) handler = getattr(super(), 'post', self.http_method_not_allowed)
return handler(request, *args, **kwargs) 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 = self.request.POST['command'] command_processor = getattr(self, 'send_{0}'.format(self.request.GET['command']), None)
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()
else:
handler = getattr(super(), 'get', self.http_method_not_allowed) handler = getattr(super(), 'get', self.http_method_not_allowed)
return handler(request, *args, **kwargs) return handler(request, *args, **kwargs)
def render_json(self, data, encoder=utils.JSONEncoder): def render_json(self, data, encoder=utils.JSONEncoder):
return JsonResponse(data, json_dumps_params={"indent": 2}, encoder=encoder) return HttpResponse(
json.dumps(data, indent=2, cls=encoder),
content_type='application/json')
class GASMixin: class GASMixin:
@ -92,10 +97,7 @@ class GASMixin:
def dispatch(self, *args, **kwargs): def dispatch(self, *args, **kwargs):
if self.check_user_forbidden(): if self.check_user_forbidden():
path = self.request.path return HttpResponseRedirect(reverse('gas:login') + '?next={}'.format(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):
@ -117,6 +119,7 @@ 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):
@ -124,6 +127,7 @@ class GASMixin:
# 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):
@ -148,10 +152,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']
javascript = gas_settings.MEDIA['js'] js = 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', [])
javascript = javascript + gas_settings.EXTRA_MEDIA.get('js', []) js = js + 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(),
@ -163,7 +167,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': javascript, 'js': js,
}) })
return ctx return ctx
@ -182,6 +186,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):
@ -211,15 +216,12 @@ 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">' '<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' %
f' opener.dismissAddAnotherPopup(window, "{obj_pk}", "{obj}");' # escape() calls force_text.
'</script></body></html>' (escape(self.object.pk), escapejs(self.object)))
) else:
return response return response
@ -253,14 +255,10 @@ class GASDeleteView(GASMixin, DeleteView):
def format_callback(obj): def format_callback(obj):
opts = obj._meta opts = obj._meta
name = capfirst(opts.verbose_name) return '%s: %s' % (capfirst(opts.verbose_name), obj)
return f'{name}: {obj}'
collector.collect([self.object]) collector.collect([self.object])
model_count = { model_count = {model._meta.verbose_name_plural: len(objs) for model, objs in collector.model_objs.items()}
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):
@ -280,7 +278,7 @@ class GASDeleteView(GASMixin, DeleteView):
}) })
return ctx return ctx
def form_valid(self, form): def delete(self, request, *args, **kwargs):
response = super().form_valid(form) response = super().delete(request, *args, **kwargs)
messages.add_message(self.request, messages.SUCCESS, self.get_deleted_text()) messages.add_message(request, messages.SUCCESS, self.get_deleted_text())
return response return response

View File

@ -1 +1 @@
Django>=3.2.13,<5.0 Django==3.2.13