Compare commits
4 Commits
880991984f
...
624b20b084
Author | SHA1 | Date |
---|---|---|
Santiago L | 624b20b084 | |
Santiago L | 049ff451ec | |
Santiago L | 3ab341a473 | |
Santiago L | 7592bff81e |
|
@ -1,12 +1,13 @@
|
|||
from functools import partial
|
||||
|
||||
from django.contrib import admin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.mail import send_mass_mail
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ngettext, gettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from .. import settings
|
||||
|
||||
from .decorators import action_with_confirmation
|
||||
from .forms import SendEmailForm
|
||||
|
||||
|
@ -18,7 +19,7 @@ class SendEmail(object):
|
|||
template = 'admin/orchestra/generic_confirmation.html'
|
||||
default_from = settings.ORCHESTRA_DEFAULT_SUPPORT_FROM_EMAIL
|
||||
__name__ = 'semd_email'
|
||||
|
||||
|
||||
def __call__(self, modeladmin, request, queryset):
|
||||
""" make this monster behave like a function """
|
||||
self.modeladmin = modeladmin
|
||||
|
@ -34,10 +35,10 @@ class SendEmail(object):
|
|||
'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
|
||||
}
|
||||
return self.write_email(request)
|
||||
|
||||
|
||||
def write_email(self, request):
|
||||
if not request.user.is_superuser:
|
||||
raise PermissionDenied
|
||||
raise PermissionDenied()
|
||||
initial={
|
||||
'email_from': self.default_from,
|
||||
'to': ' '.join(self.get_email_addresses())
|
||||
|
@ -51,7 +52,7 @@ class SendEmail(object):
|
|||
'extra_to': form.cleaned_data['extra_to'],
|
||||
'subject': form.cleaned_data['subject'],
|
||||
'message': form.cleaned_data['message'],
|
||||
|
||||
|
||||
}
|
||||
return self.confirm_email(request, **options)
|
||||
self.context.update({
|
||||
|
@ -62,10 +63,10 @@ class SendEmail(object):
|
|||
})
|
||||
# Display confirmation page
|
||||
return render(request, self.template, self.context)
|
||||
|
||||
|
||||
def get_email_addresses(self):
|
||||
return self.queryset.values_list('email', flat=True)
|
||||
|
||||
|
||||
def confirm_email(self, request, **options):
|
||||
email_from = options['email_from']
|
||||
extra_to = options['extra_to']
|
||||
|
@ -88,7 +89,7 @@ class SendEmail(object):
|
|||
)
|
||||
self.modeladmin.message_user(request, msg)
|
||||
return None
|
||||
|
||||
|
||||
form = self.form(initial={
|
||||
'email_from': email_from,
|
||||
'extra_to': ', '.join(extra_to),
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
from urllib import parse
|
||||
|
||||
from django import forms
|
||||
from django.urls import re_path as url
|
||||
from django.contrib import admin, messages
|
||||
from django.contrib.admin.options import IS_POPUP_VAR
|
||||
from django.contrib.admin.utils import unquote
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponseRedirect, Http404, HttpResponse
|
||||
from django.forms.models import BaseInlineFormSet
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import re_path as url
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.html import escape
|
||||
|
@ -19,14 +19,12 @@ from django.views.decorators.debug import sensitive_post_parameters
|
|||
|
||||
from orchestra.models.utils import has_db_field
|
||||
|
||||
from ..utils.python import random_ascii, pairwise
|
||||
|
||||
from ..utils.python import pairwise, random_ascii
|
||||
from .forms import AdminPasswordChangeForm
|
||||
#, AdminRawPasswordChangeForm
|
||||
#from django.contrib.auth.forms import AdminPasswordChangeForm
|
||||
from .utils import action_to_view
|
||||
|
||||
|
||||
sensitive_post_parameters_m = method_decorator(sensitive_post_parameters())
|
||||
|
||||
|
||||
|
@ -37,7 +35,7 @@ class ChangeListDefaultFilter(object):
|
|||
default_changelist_filters = (('my_nodes', 'True'),)
|
||||
"""
|
||||
default_changelist_filters = ()
|
||||
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
# defaults = []
|
||||
# for key, value in self.default_changelist_filters:
|
||||
|
@ -79,7 +77,7 @@ class EnhaceSearchMixin(object):
|
|||
if 'password' in lookup:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_search_results(self, request, queryset, search_term):
|
||||
""" allows to specify field <field_name>:<search_term> """
|
||||
search_fields = self.get_search_fields(request)
|
||||
|
@ -109,7 +107,7 @@ class ChangeViewActionsMixin(object):
|
|||
""" Makes actions visible on the admin change view page. """
|
||||
change_view_actions = ()
|
||||
change_form_template = 'orchestra/admin/change_form.html'
|
||||
|
||||
|
||||
def get_urls(self):
|
||||
"""Returns the additional urls for the change view links"""
|
||||
urls = super(ChangeViewActionsMixin, self).get_urls()
|
||||
|
@ -124,7 +122,7 @@ class ChangeViewActionsMixin(object):
|
|||
)
|
||||
)
|
||||
return new_urls + urls
|
||||
|
||||
|
||||
def get_change_view_actions(self, obj=None):
|
||||
""" allow customization on modelamdin """
|
||||
views = []
|
||||
|
@ -145,7 +143,7 @@ class ChangeViewActionsMixin(object):
|
|||
view.hidden = getattr(action, 'hidden', False)
|
||||
views.append(view)
|
||||
return views
|
||||
|
||||
|
||||
def change_view(self, request, object_id, **kwargs):
|
||||
if kwargs.get('extra_context', None) is None:
|
||||
kwargs['extra_context'] = {}
|
||||
|
@ -165,21 +163,21 @@ class ChangeAddFieldsMixin(object):
|
|||
change_readonly_fields = ()
|
||||
change_form = None
|
||||
add_inlines = None
|
||||
|
||||
|
||||
def get_prepopulated_fields(self, request, obj=None):
|
||||
if not obj:
|
||||
return super(ChangeAddFieldsMixin, self).get_prepopulated_fields(request, obj)
|
||||
return {}
|
||||
|
||||
|
||||
def get_change_readonly_fields(self, request, obj=None):
|
||||
return self.change_readonly_fields
|
||||
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
fields = super(ChangeAddFieldsMixin, self).get_readonly_fields(request, obj)
|
||||
if obj:
|
||||
return fields + self.get_change_readonly_fields(request, obj)
|
||||
return fields
|
||||
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
if not obj:
|
||||
if self.add_fieldsets:
|
||||
|
@ -187,7 +185,7 @@ class ChangeAddFieldsMixin(object):
|
|||
elif self.add_fields:
|
||||
return [(None, {'fields': self.add_fields})]
|
||||
return super(ChangeAddFieldsMixin, self).get_fieldsets(request, obj)
|
||||
|
||||
|
||||
def get_inline_instances(self, request, obj=None):
|
||||
""" add_inlines and inline.parent_object """
|
||||
if obj:
|
||||
|
@ -198,7 +196,7 @@ class ChangeAddFieldsMixin(object):
|
|||
for inline in inlines:
|
||||
inline.parent_object = obj
|
||||
return inlines
|
||||
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
""" Use special form during user creation """
|
||||
defaults = {}
|
||||
|
@ -218,13 +216,13 @@ class ExtendedModelAdmin(ChangeViewActionsMixin,
|
|||
EnhaceSearchMixin,
|
||||
admin.ModelAdmin):
|
||||
list_prefetch_related = None
|
||||
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(ExtendedModelAdmin, self).get_queryset(request)
|
||||
if self.list_prefetch_related:
|
||||
qs = qs.prefetch_related(*self.list_prefetch_related)
|
||||
return qs
|
||||
|
||||
|
||||
def get_object(self, request, object_id, from_field=None):
|
||||
obj = super(ExtendedModelAdmin, self).get_object(request, object_id, from_field)
|
||||
if obj is None:
|
||||
|
@ -237,7 +235,7 @@ class ExtendedModelAdmin(ChangeViewActionsMixin,
|
|||
class ChangePasswordAdminMixin(object):
|
||||
change_password_form = AdminPasswordChangeForm
|
||||
change_user_password_template = 'admin/orchestra/change_password.html'
|
||||
|
||||
|
||||
def get_urls(self):
|
||||
opts = self.model._meta
|
||||
info = opts.app_label, opts.model_name
|
||||
|
@ -249,14 +247,14 @@ class ChangePasswordAdminMixin(object):
|
|||
self.admin_site.admin_view(self.show_hash),
|
||||
name='%s_%s_show_hash' % info)
|
||||
] + super().get_urls()
|
||||
|
||||
|
||||
def get_change_password_username(self, obj):
|
||||
return str(obj)
|
||||
|
||||
|
||||
@sensitive_post_parameters_m
|
||||
def change_password(self, request, id, form_url=''):
|
||||
if not self.has_change_permission(request):
|
||||
raise PermissionDenied
|
||||
raise PermissionDenied()
|
||||
# TODO use this insetad of self.get_object(), in other places
|
||||
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
||||
raw = request.GET.get('raw', '0') == '1'
|
||||
|
@ -281,7 +279,7 @@ class ChangePasswordAdminMixin(object):
|
|||
for rel in account.get_related_passwords(db_field=raw):
|
||||
if not isinstance(obj, type(rel)):
|
||||
related.append(rel)
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
form = self.change_password_form(obj, request.POST, related=related, raw=raw)
|
||||
if form.is_valid():
|
||||
|
@ -293,7 +291,7 @@ class ChangePasswordAdminMixin(object):
|
|||
return HttpResponseRedirect('..')
|
||||
else:
|
||||
form = self.change_password_form(obj, related=related, raw=raw)
|
||||
|
||||
|
||||
fieldsets = [
|
||||
(obj._meta.verbose_name.capitalize(), {
|
||||
'classes': ('wide',),
|
||||
|
@ -305,7 +303,7 @@ class ChangePasswordAdminMixin(object):
|
|||
'classes': ('wide',),
|
||||
'fields': ('password_%i' % ix,) if raw else ('password1_%i' % ix, 'password2_%i' % ix)
|
||||
}))
|
||||
|
||||
|
||||
obj_username = self.get_change_password_username(obj)
|
||||
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
||||
context = {
|
||||
|
@ -331,9 +329,9 @@ class ChangePasswordAdminMixin(object):
|
|||
}
|
||||
context.update(admin.site.each_context(request))
|
||||
return TemplateResponse(request, self.change_user_password_template, context)
|
||||
|
||||
|
||||
def show_hash(self, request, id):
|
||||
if not request.user.is_superuser:
|
||||
raise PermissionDenied
|
||||
raise PermissionDenied()
|
||||
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
||||
return HttpResponse(obj.password)
|
||||
|
|
|
@ -143,6 +143,8 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#auth-password-validators
|
||||
|
@ -233,6 +235,7 @@ FLUENT_DASHBOARD_ICON_THEME = '../orchestra/icons'
|
|||
|
||||
# Django-celery
|
||||
import djcelery
|
||||
|
||||
djcelery.setup_loader()
|
||||
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import sys
|
||||
from contextlib import ContextDecorator
|
||||
from threading import local
|
||||
|
||||
from django.contrib.admin.models import LogEntry
|
||||
from django.db.models.signals import pre_delete, post_save, m2m_changed
|
||||
from django.db.models.signals import m2m_changed, post_save, pre_delete
|
||||
from django.dispatch import receiver
|
||||
from django.utils.decorators import ContextDecorator
|
||||
|
||||
from orchestra.utils.python import OrderedSet
|
||||
|
||||
from . import manager, Operation, helpers
|
||||
from . import Operation, helpers, manager
|
||||
from .middlewares import OperationsMiddleware
|
||||
from .models import BackendLog, BackendOperation
|
||||
|
||||
|
@ -37,7 +37,7 @@ def m2m_collector(sender, *args, **kwargs):
|
|||
class orchestrate(ContextDecorator):
|
||||
"""
|
||||
Context manager for triggering backend operations out of request-response cycle, e.g. shell
|
||||
|
||||
|
||||
with orchestrate():
|
||||
user = SystemUser.objects.get(username='rata')
|
||||
user.shell = '/dev/null'
|
||||
|
@ -46,7 +46,7 @@ class orchestrate(ContextDecorator):
|
|||
thread_locals = local()
|
||||
thread_locals.pending_operations = None
|
||||
thread_locals.route_cache = None
|
||||
|
||||
|
||||
@classmethod
|
||||
def collect(cls, action, **kwargs):
|
||||
""" Collects all pending operations derived from model signals """
|
||||
|
@ -57,14 +57,14 @@ class orchestrate(ContextDecorator):
|
|||
kwargs['route_cache'] = cls.thread_locals.route_cache
|
||||
instance = kwargs.pop('instance')
|
||||
manager.collect(instance, action, **kwargs)
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
cls = type(self)
|
||||
self.old_pending_operations = cls.thread_locals.pending_operations
|
||||
cls.thread_locals.pending_operations = OrderedSet()
|
||||
self.old_route_cache = cls.thread_locals.route_cache
|
||||
cls.thread_locals.route_cache = {}
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
cls = type(self)
|
||||
if not exc_type:
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
Django==2.2.24
|
||||
django-fluent-dashboard==1.0.1
|
||||
django-admin-tools==0.9.1
|
||||
django-extensions==3.1.3
|
||||
django-celery==3.2.1
|
||||
celery==3.1.23
|
||||
kombu==3.0.35
|
||||
Django==3.2.23
|
||||
django-fluent-dashboard==2.0
|
||||
django-admin-tools==0.9.3
|
||||
django-extensions==3.2.3
|
||||
django-celery==3.3.1
|
||||
celery<4.0,>=3.1.15
|
||||
kombu==3.0.37
|
||||
billiard==3.3.0.23
|
||||
Markdown==3.3.4
|
||||
djangorestframework==3.12.4
|
||||
Pygments==2.9.0
|
||||
django-filter==2.4.0
|
||||
Markdown==3.5.1
|
||||
djangorestframework==3.14.0
|
||||
Pygments==2.17.2
|
||||
django-filter==23.4
|
||||
jsonfield==3.1.0
|
||||
python-dateutil>=2.7.0
|
||||
python-dateutil==2.8.2
|
||||
passlib==1.7.4
|
||||
django-iban==0.3.0
|
||||
django-iban==0.3.1
|
||||
requests
|
||||
phonenumbers==8.12.27
|
||||
phonenumbers==8.13.26
|
||||
django-countries
|
||||
django-localflavor==3.1
|
||||
django-localflavor==4.0
|
||||
amqp
|
||||
anyjson
|
||||
pytz
|
||||
|
|
Loading…
Reference in New Issue