2016-03-31 16:02:50 +00:00
|
|
|
from functools import partial, wraps
|
|
|
|
|
2014-10-07 13:50:59 +00:00
|
|
|
from django.contrib import messages
|
2015-04-04 17:44:07 +00:00
|
|
|
from django.contrib.admin import helpers
|
2015-10-05 13:31:08 +00:00
|
|
|
from django.contrib.admin.utils import NestedObjects, quote
|
2015-04-04 17:44:07 +00:00
|
|
|
from django.contrib.auth import get_permission_codename
|
2021-04-21 12:27:18 +00:00
|
|
|
from django.urls import reverse, NoReverseMatch
|
2015-04-04 17:44:07 +00:00
|
|
|
from django.db import router
|
2014-11-21 17:18:59 +00:00
|
|
|
from django.shortcuts import redirect, render
|
2015-04-04 17:44:07 +00:00
|
|
|
from django.template.response import TemplateResponse
|
2014-11-21 17:18:59 +00:00
|
|
|
from django.utils import timezone
|
2015-04-04 17:44:07 +00:00
|
|
|
from django.utils.encoding import force_text
|
|
|
|
from django.utils.html import format_html
|
|
|
|
from django.utils.text import capfirst
|
2015-09-18 11:29:52 +00:00
|
|
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
2014-10-07 13:50:59 +00:00
|
|
|
|
2014-11-21 17:18:59 +00:00
|
|
|
from orchestra.core import services
|
2014-10-07 13:50:59 +00:00
|
|
|
|
2014-11-27 19:17:26 +00:00
|
|
|
from . import settings
|
|
|
|
|
2014-10-07 13:50:59 +00:00
|
|
|
|
2014-11-21 15:39:41 +00:00
|
|
|
def list_contacts(modeladmin, request, queryset):
|
2015-07-21 10:44:32 +00:00
|
|
|
ids = queryset.order_by().values_list('id', flat=True).distinct()
|
2014-11-21 15:39:41 +00:00
|
|
|
if not ids:
|
2015-03-26 16:00:30 +00:00
|
|
|
messages.warning(request, "Select at least one account.")
|
2014-11-21 15:39:41 +00:00
|
|
|
return
|
|
|
|
url = reverse('admin:contacts_contact_changelist')
|
|
|
|
url += '?account__in=%s' % ','.join(map(str, ids))
|
|
|
|
return redirect(url)
|
2015-07-20 12:51:30 +00:00
|
|
|
list_contacts.short_description = _("List contacts")
|
2014-11-21 17:18:59 +00:00
|
|
|
|
|
|
|
|
2015-07-21 10:44:32 +00:00
|
|
|
def list_accounts(modeladmin, request, queryset):
|
|
|
|
accounts = queryset.order_by().values_list('account_id', flat=True).distinct()
|
|
|
|
if not accounts:
|
|
|
|
messages.warning(request, "Select at least one instance.")
|
|
|
|
return
|
|
|
|
url = reverse('admin:contacts_contact_changelist')
|
|
|
|
url += '?id__in=%s' % ','.join(map(str, accounts))
|
|
|
|
return redirect(url)
|
|
|
|
list_accounts.short_description = _("List accounts")
|
|
|
|
|
|
|
|
|
2014-11-21 17:18:59 +00:00
|
|
|
def service_report(modeladmin, request, queryset):
|
2014-11-27 19:17:26 +00:00
|
|
|
# TODO resources
|
2014-11-21 17:18:59 +00:00
|
|
|
accounts = []
|
2014-11-24 14:39:41 +00:00
|
|
|
fields = []
|
2015-04-04 17:44:07 +00:00
|
|
|
registered_services = services.get()
|
2014-11-24 14:39:41 +00:00
|
|
|
# First we get related manager names to fire a prefetch related
|
2015-04-04 17:44:07 +00:00
|
|
|
for name, field in queryset.model._meta.fields_map.items():
|
|
|
|
model = field.related_model
|
|
|
|
if model in registered_services and model != queryset.model:
|
2014-11-24 14:39:41 +00:00
|
|
|
fields.append((model, name))
|
2015-10-07 22:05:00 +00:00
|
|
|
fields = sorted(fields, key=lambda f: f[0]._meta.verbose_name_plural.lower())
|
2014-11-24 14:39:41 +00:00
|
|
|
fields = [field for model, field in fields]
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2014-11-24 14:39:41 +00:00
|
|
|
for account in queryset.prefetch_related(*fields):
|
2014-11-21 17:18:59 +00:00
|
|
|
items = []
|
2014-11-24 14:39:41 +00:00
|
|
|
for field in fields:
|
|
|
|
related_manager = getattr(account, field)
|
|
|
|
items.append((related_manager.model._meta, related_manager.all()))
|
2014-11-21 17:18:59 +00:00
|
|
|
accounts.append((account, items))
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2014-11-21 17:18:59 +00:00
|
|
|
context = {
|
|
|
|
'accounts': accounts,
|
|
|
|
'date': timezone.now().today()
|
|
|
|
}
|
2014-11-27 19:17:26 +00:00
|
|
|
return render(request, settings.ACCOUNTS_SERVICE_REPORT_TEMPLATE, context)
|
2015-04-02 16:14:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
def delete_related_services(modeladmin, request, queryset):
|
2015-04-04 17:44:07 +00:00
|
|
|
opts = modeladmin.model._meta
|
|
|
|
app_label = opts.app_label
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
using = router.db_for_write(modeladmin.model)
|
|
|
|
collector = NestedObjects(using=using)
|
|
|
|
collector.collect(queryset)
|
|
|
|
registered_services = services.get()
|
|
|
|
related_services = []
|
|
|
|
to_delete = []
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
admin_site = modeladmin.admin_site
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-05-19 13:27:04 +00:00
|
|
|
def format(obj, account=False):
|
2015-04-04 17:44:07 +00:00
|
|
|
has_admin = obj.__class__ in admin_site._registry
|
|
|
|
opts = obj._meta
|
|
|
|
no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), force_text(obj))
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
if has_admin:
|
|
|
|
try:
|
2015-10-05 13:31:08 +00:00
|
|
|
admin_url = reverse(
|
|
|
|
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
|
|
|
|
None, (quote(obj._get_pk_val()),)
|
2015-04-04 17:44:07 +00:00
|
|
|
)
|
|
|
|
except NoReverseMatch:
|
|
|
|
# Change url doesn't exist -- don't display link to edit
|
|
|
|
return no_edit_link
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
# Display a link to the admin page.
|
2015-05-19 13:27:04 +00:00
|
|
|
context = (capfirst(opts.verbose_name), admin_url, obj)
|
|
|
|
if account:
|
|
|
|
context += (_("services to delete:"),)
|
|
|
|
return format_html('{} <a href="{}">{}</a> {}', *context)
|
|
|
|
return format_html('{}: <a href="{}">{}</a>', *context)
|
2015-04-04 17:44:07 +00:00
|
|
|
else:
|
|
|
|
# Don't display link to edit, because it either has no
|
|
|
|
# admin or is edited inline.
|
|
|
|
return no_edit_link
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
def format_nested(objs, result):
|
|
|
|
if isinstance(objs, list):
|
|
|
|
current = []
|
|
|
|
for obj in objs:
|
|
|
|
format_nested(obj, current)
|
|
|
|
result.append(current)
|
|
|
|
else:
|
|
|
|
result.append(format(objs))
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-05-19 13:27:04 +00:00
|
|
|
for nested in collector.nested():
|
|
|
|
if isinstance(nested, list):
|
|
|
|
# Is lists of objects
|
2015-04-04 17:44:07 +00:00
|
|
|
current = []
|
|
|
|
is_service = False
|
2015-05-19 13:27:04 +00:00
|
|
|
for service in nested:
|
2015-04-04 17:44:07 +00:00
|
|
|
if type(service) in registered_services:
|
|
|
|
if service == main_systemuser:
|
|
|
|
continue
|
|
|
|
current.append(format(service))
|
|
|
|
to_delete.append(service)
|
|
|
|
is_service = True
|
|
|
|
elif is_service and isinstance(service, list):
|
|
|
|
nested = []
|
|
|
|
format_nested(service, nested)
|
2016-04-30 12:01:29 +00:00
|
|
|
current.append(nested[0])
|
2015-04-04 17:44:07 +00:00
|
|
|
is_service = False
|
|
|
|
else:
|
|
|
|
is_service = False
|
|
|
|
related_services.append(current)
|
2015-05-19 13:27:04 +00:00
|
|
|
elif isinstance(nested, modeladmin.model):
|
|
|
|
# Is account
|
2015-04-04 17:44:07 +00:00
|
|
|
# Prevent the deletion of the main system user, which will delete the account
|
2015-05-19 13:27:04 +00:00
|
|
|
main_systemuser = nested.main_systemuser
|
|
|
|
related_services.append(format(nested, account=True))
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
# The user has already confirmed the deletion.
|
|
|
|
# Do the deletion and return a None to display the change list view again.
|
|
|
|
if request.POST.get('post'):
|
2015-09-18 11:29:52 +00:00
|
|
|
accounts = len(queryset)
|
|
|
|
msg = _("Related services deleted and account disabled.")
|
|
|
|
for account in queryset:
|
|
|
|
account.is_active = False
|
|
|
|
account.save(update_fields=('is_active',))
|
|
|
|
modeladmin.log_change(request, account, msg)
|
|
|
|
if accounts:
|
|
|
|
relateds = len(to_delete)
|
2015-04-04 17:44:07 +00:00
|
|
|
for obj in to_delete:
|
|
|
|
obj_display = force_text(obj)
|
|
|
|
modeladmin.log_deletion(request, obj, obj_display)
|
|
|
|
obj.delete()
|
2015-09-18 11:29:52 +00:00
|
|
|
context = {
|
|
|
|
'accounts': accounts,
|
|
|
|
'relateds': relateds,
|
|
|
|
}
|
|
|
|
msg = _("Successfully disabled %(accounts)d account and deleted %(relateds)d related services.") % context
|
|
|
|
modeladmin.message_user(request, msg, messages.SUCCESS)
|
2015-04-04 17:44:07 +00:00
|
|
|
# Return None to display the change list page again.
|
|
|
|
return None
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-04-04 17:44:07 +00:00
|
|
|
if len(queryset) == 1:
|
|
|
|
objects_name = force_text(opts.verbose_name)
|
|
|
|
else:
|
|
|
|
objects_name = force_text(opts.verbose_name_plural)
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2016-10-03 08:59:47 +00:00
|
|
|
model_count = {}
|
|
|
|
for model, objs in collector.model_objs.items():
|
|
|
|
count = 0
|
|
|
|
# discount main systemuser
|
|
|
|
if model is modeladmin.model.main_systemuser.field.rel.to:
|
|
|
|
count = len(objs) - 1
|
|
|
|
# Discount account
|
|
|
|
elif model is not modeladmin.model and model in registered_services:
|
|
|
|
count = len(objs)
|
|
|
|
if count:
|
|
|
|
model_count[model._meta.verbose_name_plural] = count
|
|
|
|
if not model_count:
|
|
|
|
modeladmin.message_user(request, _("Nothing to delete"), messages.WARNING)
|
|
|
|
return None
|
2015-04-04 17:44:07 +00:00
|
|
|
context = dict(
|
2015-09-18 11:29:52 +00:00
|
|
|
admin_site.each_context(request),
|
2015-04-04 17:44:07 +00:00
|
|
|
title=_("Are you sure?"),
|
|
|
|
objects_name=objects_name,
|
|
|
|
deletable_objects=[related_services],
|
2016-04-30 12:01:29 +00:00
|
|
|
model_count=dict(model_count).items(),
|
2015-04-04 17:44:07 +00:00
|
|
|
queryset=queryset,
|
|
|
|
opts=opts,
|
|
|
|
action_checkbox_name=helpers.ACTION_CHECKBOX_NAME,
|
|
|
|
)
|
2015-09-18 11:29:52 +00:00
|
|
|
request.current_app = admin_site.name
|
2015-04-04 17:44:07 +00:00
|
|
|
# Display the confirmation page
|
2015-09-18 11:29:52 +00:00
|
|
|
template = 'admin/%s/%s/delete_related_services_confirmation.html' % (app_label, opts.model_name)
|
|
|
|
return TemplateResponse(request, template, context)
|
2015-04-04 17:44:07 +00:00
|
|
|
delete_related_services.short_description = _("Delete related services")
|
2015-09-18 11:29:52 +00:00
|
|
|
|
|
|
|
|
2016-03-31 16:02:50 +00:00
|
|
|
def disable_selected(modeladmin, request, queryset, disable=True):
|
2015-09-18 11:29:52 +00:00
|
|
|
opts = modeladmin.model._meta
|
|
|
|
app_label = opts.app_label
|
2016-03-31 16:02:50 +00:00
|
|
|
verbose_action_name = _("disabled") if disable else _("enabled")
|
2015-09-18 11:29:52 +00:00
|
|
|
# The user has already confirmed the deletion.
|
|
|
|
# Do the disable and return a None to display the change list view again.
|
|
|
|
if request.POST.get('post'):
|
|
|
|
n = 0
|
|
|
|
for account in queryset:
|
2016-03-31 16:02:50 +00:00
|
|
|
account.disable() if disable else account.enable()
|
|
|
|
modeladmin.log_change(request, account, verbose_action_name.capitalize())
|
2015-09-18 11:29:52 +00:00
|
|
|
n += 1
|
|
|
|
modeladmin.message_user(request, ungettext(
|
2016-03-31 16:02:50 +00:00
|
|
|
_("One account has been successfully %s.") % verbose_action_name,
|
|
|
|
_("%i accounts have been successfully %s.") % (n, verbose_action_name),
|
2015-09-18 11:29:52 +00:00
|
|
|
n)
|
|
|
|
)
|
|
|
|
return None
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
user = request.user
|
|
|
|
admin_site = modeladmin.admin_site
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
def format(obj):
|
|
|
|
has_admin = obj.__class__ in admin_site._registry
|
|
|
|
opts = obj._meta
|
|
|
|
no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), force_text(obj))
|
|
|
|
if has_admin:
|
|
|
|
try:
|
|
|
|
admin_url = reverse(
|
|
|
|
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
|
|
|
|
None,
|
|
|
|
(quote(obj._get_pk_val()),)
|
|
|
|
)
|
|
|
|
except NoReverseMatch:
|
|
|
|
# Change url doesn't exist -- don't display link to edit
|
|
|
|
return no_edit_link
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts))
|
|
|
|
if not user.has_perm(p):
|
|
|
|
perms_needed.add(opts.verbose_name)
|
|
|
|
# Display a link to the admin page.
|
|
|
|
context = (capfirst(opts.verbose_name), admin_url, obj)
|
|
|
|
return format_html('{}: <a href="{}">{}</a>', *context)
|
|
|
|
else:
|
|
|
|
# Don't display link to edit, because it either has no
|
|
|
|
# admin or is edited inline.
|
|
|
|
return no_edit_link
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
display = []
|
|
|
|
for account in queryset:
|
|
|
|
current = []
|
|
|
|
for related in account.get_services_to_disable():
|
|
|
|
current.append(format(related))
|
|
|
|
display.append([format(account), current])
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
if len(queryset) == 1:
|
|
|
|
objects_name = force_text(opts.verbose_name)
|
|
|
|
else:
|
|
|
|
objects_name = force_text(opts.verbose_name_plural)
|
2021-04-21 12:27:18 +00:00
|
|
|
|
2015-09-18 11:29:52 +00:00
|
|
|
context = dict(
|
|
|
|
admin_site.each_context(request),
|
2016-03-31 16:02:50 +00:00
|
|
|
action_name='disable_selected' if disable else 'enable_selected',
|
|
|
|
disable=disable,
|
2015-09-18 11:29:52 +00:00
|
|
|
title=_("Are you sure?"),
|
|
|
|
objects_name=objects_name,
|
|
|
|
deletable_objects=display,
|
|
|
|
queryset=queryset,
|
|
|
|
opts=opts,
|
|
|
|
action_checkbox_name=helpers.ACTION_CHECKBOX_NAME,
|
|
|
|
)
|
|
|
|
request.current_app = admin_site.name
|
|
|
|
template = 'admin/%s/%s/disable_selected_confirmation.html' % (app_label, opts.model_name)
|
|
|
|
return TemplateResponse(request, template, context)
|
|
|
|
disable_selected.short_description = _("Disable selected accounts")
|
2016-03-31 16:02:50 +00:00
|
|
|
disable_selected.url_name = 'disable'
|
2015-09-18 11:29:52 +00:00
|
|
|
disable_selected.tool_description = _("Disable")
|
2016-03-31 16:02:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
enable_selected = partial(disable_selected, disable=False)
|
|
|
|
enable_selected.__name__ = 'enable_selected'
|
|
|
|
enable_selected.url_name = 'enable'
|
|
|
|
enable_selected.tool_description = _("Enable")
|