Sortable columns for all listing pages.

fixes #154
This commit is contained in:
Antoine Nguyen
2013-05-04 09:46:26 +02:00
parent 0db2d028f1
commit e834a3c4ac
5 changed files with 75 additions and 102 deletions
+20 -35
View File
@@ -1,46 +1,31 @@
# coding: utf-8
from django.utils.translation import ugettext as _
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from modoboa.lib.webutils import ajax_simple_response
from modoboa.lib import parameters
from modoboa.lib.templatetags.libextras import pagination_bar
from modoboa.admin.tables import *
from exceptions import *
def render_listing(request, objtype, **kwargs):
"""Common function to render a listing
All listing pages available into the admin application use the
same layout, rendered by this function.
def get_sort_order(qdict, default, allowed_values=None):
"""Return a sort order from a querydict object
:param request: a ``Request`` object
:param objtype: the object type's name (lowercase)
:param QueryDict qdict: the object to analyse
:param string default: the default sort order if no one is found
:param list allowed_values: an optional list of allowed values
:return: a 2uple of strings
"""
tblclass = "%sTable" % objtype.capitalize()
if not globals().has_key(tblclass):
raise AdminError(_("Unknown object type"))
tblclass = globals()[tblclass]
if request.GET.has_key("domid"):
kwargs["domid"] = request.GET["domid"]
sort_order = qdict.get("sort_order", default)
if sort_order.startswith("-"):
sort_dir = "-"
sort_order = sort_order[1:]
else:
kwargs["domid"] = ""
paginator = Paginator(kwargs["objects"],
int(parameters.get_admin("ITEMS_PER_PAGE")))
sort_dir = ""
if allowed_values is not None and not sort_order in allowed_values:
return (default, "")
return (sort_order, sort_dir)
def get_listing_page(objects, pagenum):
paginator = Paginator(objects, int(parameters.get_admin("ITEMS_PER_PAGE")))
try:
pagenum = request.GET.get("page", "1")
except ValueError:
pagenum = 1
try:
page = paginator.page(pagenum)
page = paginator.page(int(pagenum))
except (EmptyPage, PageNotAnInteger):
page = paginator.page(paginator.num_pages)
return ajax_simple_response({
"table" : tblclass(request, page.object_list).render(),
"page" : page.number,
"paginbar" : pagination_bar(page),
"handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES",
raise_error=False),
"auto_account_removal": parameters.get_admin("AUTO_ACCOUNT_REMOVAL")
})
return page
+7 -32
View File
@@ -11,10 +11,13 @@ class DomainsTable(tables.Table):
name = tables.LinkColumn(
"name", label=ugettext_lazy("Name"),
urlpattern="modoboa.admin.views.editdomain",
title=_("Edit domain"), modal=True, modalcb="admin.domainform_cb"
)
domaliases = tables.Column("domainalias_set",
label=ugettext_lazy("Alias(es)"), safe=True)
title=_("Edit domain"), modal=True, modalcb="admin.domainform_cb",
sortable=True, sort_order="name"
)
domaliases = tables.Column(
"domainalias_set", label=ugettext_lazy("Alias(es)"), safe=True,
sortable=True, sort_order="domainalias__name"
)
actions = tables.ActionColumn("actions", label=ugettext_lazy("Actions"),
defvalue=domain_actions)
@@ -46,31 +49,3 @@ class ExtensionsTable(tables.Table):
descr = tables.Column("description", label=ugettext_lazy("Description"))
cols_order = ["selection", "label", "version", "descr"]
class IdentitiesTable(tables.Table):
idkey = "id"
styles = "table"
tags = tables.Column("tags", label=ugettext_lazy("Tags"), safe=True)
identity = tables.LinkColumn(
"identity", label=ugettext_lazy("Email/Username"),
modal=True,
urlpattern={"User" : "modoboa.admin.views.editaccount",
"Alias" : "modoboa.admin.views.editalias_dispatcher"},
modalcb={"User" : "admin.editaccount_cb", "Alias" : "admin.aliasform_cb"}
)
name_or_rcpt = tables.Column("name_or_rcpt", label=ugettext_lazy("Fullname/Recipient"))
actions = tables.ActionColumn("actions", label=ugettext_lazy("Actions"),
defvalue=identity_actions)
cols_order = ["identity", "name_or_rcpt", "tags", "actions"]
def __init__(self, request, identities):
super(IdentitiesTable, self).__init__(request)
self.populate(self._rows_from_model(identities, True))
def row_class(self, request, obj):
if obj.__class__.__name__ == "User" and not obj.is_active:
return "muted"
if not obj.enabled:
return "muted"
return ""
@@ -2,9 +2,9 @@
<table id="{{ tableid }}" class="table {{ styles }}">
<thead>
<tr>
<th id="identity" width="">{% trans "Name" %}</th>
<th id="name_or_rcpt" width="">{% trans "Fullname/Recipient" %}</th>
<th id="tags" width="">{% trans "Tags" %}</th>
<th id="identity" class="sortable" data-sort_order="identity" width="">{% trans "Name" %}</th>
<th id="name_or_rcpt" class="sortable" data-sort_order="name_or_rcpt" width="">{% trans "Fullname/Recipient" %}</th>
<th id="tags" class="sortable" data-sort_order="tags" width="">{% trans "Tags" %}</th>
<th id="actions" width="">{% trans "Actions" %}</th>
</tr>
</thead>
+44 -31
View File
@@ -6,14 +6,15 @@ from django.contrib.auth.decorators \
import login_required, permission_required, user_passes_test
from django.db.models import Q
from django.shortcuts import render
from django.template.loader import render_to_string
from django.db import transaction, IntegrityError
import cStringIO
import csv
from lib import *
from lib import get_sort_order, get_listing_page
from forms import *
from models import *
from modoboa.admin.tables import *
from modoboa.admin.tables import DomainsTable
from modoboa.lib import events, parameters
from modoboa.lib.exceptions import *
from modoboa.lib.webutils \
@@ -21,41 +22,53 @@ from modoboa.lib.webutils \
from modoboa.lib.emailutils import split_mailbox
from modoboa.lib.models import Parameter
from modoboa.lib.formutils import CreationWizard
from modoboa.lib.templatetags.libextras import pagination_bar
@login_required
def index(request):
return HttpResponseRedirect(reverse(domains))
@login_required
@user_passes_test(lambda u: u.has_perm("admin.view_domains") or u.has_perm("admin.view_mailboxes"))
def _domains(request):
sort_order, sort_dir = get_sort_order(request.GET, "name")
domains = request.user.get_domains()
squery = request.GET.get("searchquery", None)
if squery is not None:
q = Q(name__contains=squery)
q |= Q(domainalias__name__contains=squery)
domains = domains.filter(q).distinct()
return render_listing(request, "domains", objects=domains)
if sort_order in ["name", "domainalias__name"]:
domains = domains.order_by("%s%s" % (sort_dir, sort_order))
page = get_listing_page(domains, request.GET.get("page", 1))
return ajax_simple_response({
"table": DomainsTable(request, page.object_list).render(),
"page": page.number,
"paginbar": pagination_bar(page),
"handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES",
raise_error=False),
"auto_account_removal": parameters.get_admin("AUTO_ACCOUNT_REMOVAL")
})
@login_required
def domains(request, tplname="admin/domains.html"):
if not request.user.has_perm("admin.view_domains"):
if request.user.has_perm("admin.view_mailboxes"):
return HttpResponseRedirect(reverse(identities))
return HttpResponseRedirect(reverse("modoboa.userprefs.views.index"))
return render(request, tplname, {
"selection" : "domains"
})
return render(request, tplname, {"selection": "domains"})
@login_required
@permission_required("admin.add_user")
def domains_list(request):
doms = map(lambda dom: dom.name, request.user.get_domains())
doms = [dom.name for dom in request.user.get_domains()]
return ajax_simple_response(doms)
def _validate_domain(request, form, successmsg, commonctx, tplname,
callback=None, tpl_form_name="form"):
"""Domain form validation
@@ -77,12 +90,13 @@ def _validate_domain(request, form, successmsg, commonctx, tplname,
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
@login_required
@permission_required("admin.add_domain")
@transaction.commit_on_success
def newdomain(request, tplname="common/wizard_forms.html"):
events.raiseEvent("CanCreate", request.user, "domains")
def newdomain_cb(steps):
genform = steps[0]["form"]
genform.is_valid()
@@ -311,35 +325,39 @@ def delalias(request):
def deldlist(request):
return _del_alias(request, "Distribution list deleted", "Distribution lists deleted")
@login_required
@permission_required("admin.delete_alias")
@transaction.commit_on_success
def delforward(request):
return _del_alias(request, "Forward deleted", "Forwards deleted")
@login_required
@user_passes_test(lambda u: u.has_perm("admin.add_user") or u.has_perm("admin.add_alias"))
def _identities(request):
idents_list = request.user.get_identities(request.GET)
objects = sorted(idents_list, key=lambda o: o.identity)
paginator = Paginator(objects, int(parameters.get_admin("ITEMS_PER_PAGE")))
pagenum = int(request.GET.get("page", "1"))
try:
page = paginator.page(pagenum)
except (EmptyPage, PageNotAnInteger):
page = paginator.page(paginator.num_pages)
sort_order, sort_dir = get_sort_order(request.GET, "identity",
["identity", "name_or_rcpt", "tags"])
if sort_order in ["identity", "name_or_rcpt"]:
objects = sorted(idents_list, key=lambda o: getattr(o, sort_order),
reverse=sort_dir == '-')
else:
objects = sorted(idents_list, key=lambda o: o.tags[0],
reverse=sort_dir == '-')
page = get_listing_page(objects, request.GET.get("page", 1))
return ajax_simple_response({
"table" : _render_to_string(request, "admin/identities_table.html", {
"identities" : page.object_list,
"tableid" : "objects_table"
"table": _render_to_string(request, "admin/identities_table.html", {
"identities": page.object_list,
"tableid": "objects_table"
}),
"handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES", raise_error=False),
"page" : page.number,
"paginbar" : pagination_bar(page)
"handle_mailboxes": parameters.get_admin("HANDLE_MAILBOXES",
raise_error=False),
"page": page.number,
"paginbar": pagination_bar(page)
})
@login_required
@user_passes_test(lambda u: u.has_perm("admin.add_user") or u.has_perm("admin.add_alias"))
def identities(request, tplname="admin/identities.html"):
@@ -365,14 +383,9 @@ def mboxes_list(request):
@login_required
@permission_required("admin.add_mailbox")
def list_quotas(request, tplname="admin/quotas.html"):
sort_order = request.GET.get("sort_order", "address")
sort_order, sort_dir = get_sort_order(request.GET, "address")
mboxes = request.user.get_mailboxes(request.GET.get("searchquery", None))
mboxes = mboxes.exclude(quota=0)
if sort_order.startswith("-"):
sort_dir = "-"
sort_order = sort_order[1:]
else:
sort_dir = ""
if sort_order in ["address", "quota", "quota_value__bytes"]:
mboxes = mboxes.order_by("%s%s" % (sort_dir, sort_order))
elif sort_order == "quota_usage":
+1 -1
View File
@@ -2,7 +2,7 @@
<tr>
{% for c in table.columns %}
{% if c.sortable %}
<th id="{{ c.name }}" class="sortable" width="{{ c.width }}" align="{{ c.align }}">
<th id="{{ c.name }}" class="sortable" data-sort_order="{{ c.sort_order }}" width="{{ c.width }}" align="{{ c.align }}">
{% else %}
<th id="{{ c.name }}" width="{{ c.width }}">
{% endif %}