mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
@@ -1,5 +1,6 @@
|
||||
"""Models related to aliases management."""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
@@ -84,6 +85,10 @@ class Alias(AdminObject):
|
||||
altype = self.type
|
||||
return [{"name": altype, "label": labels[altype], "type": "idt"}]
|
||||
|
||||
def get_absolute_url(self):
|
||||
"""Return detail url for this alias."""
|
||||
return reverse("admin:alias_detail", args=[self.pk])
|
||||
|
||||
def post_create(self, creator):
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
super(Alias, self).post_create(creator)
|
||||
|
||||
@@ -155,13 +155,11 @@ class Mailbox(AdminObject):
|
||||
|
||||
:rtype: list of string
|
||||
"""
|
||||
aliases = []
|
||||
qset = (
|
||||
self.aliasrecipient_set.select_related("alias")
|
||||
.filter(alias__internal=False)
|
||||
)
|
||||
for alr in qset:
|
||||
aliases += [alr.alias.address]
|
||||
aliases = [alr.alias.address for alr in qset]
|
||||
return aliases
|
||||
|
||||
@property
|
||||
@@ -235,8 +233,8 @@ class Mailbox(AdminObject):
|
||||
self.quota = 0
|
||||
elif int(value) > self.domain.quota and not override_rules:
|
||||
raise lib_exceptions.BadRequest(
|
||||
_("Quota is greater than the allowed domain's limit (%dM)")
|
||||
% self.domain.quota
|
||||
_("Quota is greater than the allowed domain's limit (%dM)") %
|
||||
self.domain.quota
|
||||
)
|
||||
else:
|
||||
self.quota = value
|
||||
|
||||
@@ -7,3 +7,5 @@ extra_domain_actions = django.dispatch.Signal(
|
||||
providing_args=["user", "domain"])
|
||||
extra_domain_dashboard_widgets = django.dispatch.Signal(
|
||||
providing_args=["user", "domain"])
|
||||
extra_account_dashboard_widgets = django.dispatch.Signal(
|
||||
providing_args=["user", "account"])
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
{% extends "admin/header.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load admin_tags %}
|
||||
{% load lib_tags %}
|
||||
|
||||
{% block leftcol %}
|
||||
<ul class="nav nav-sidebar">
|
||||
{% identities_menu user "identities" False %}
|
||||
</ul>
|
||||
|
||||
{% get_extra_admin_content user "leftcol" selection %}
|
||||
{% endblock %}
|
||||
|
||||
{% block apparea %}
|
||||
<h2>{{ object }}{% if not object.is_active %} <small>{% trans "(disabled)" %}</small>{% endif %}</h2>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Summary" %}</h3>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{% trans "Full name" %}</th><td>{{ object.fullname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Role" %}</th><td>{{ object.role }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Created" %}</th><td>{{ object.date_joined|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Last login" %}</th><td>{{ object.last_login|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Secondary email" %}</th><td>{{ object.secondary_email|default:_("Not defined") }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans "Phone number" %}</th><td>{{ object.phone_number|default:_("Not defined") }}</td>
|
||||
</tr>
|
||||
{% if user.mailbox %}
|
||||
<tr>
|
||||
<th>{% trans "Quota" %}</th>
|
||||
<td>{% include "common/progressbar.html" with id='quotabar' value=user.mailbox.get_quota_in_percent %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if domains %}
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Administered domains" %}</h3>
|
||||
</div>
|
||||
<table class="table">
|
||||
{% for domain in domains %}
|
||||
<tr><td>{{ domain }}</td></tr>
|
||||
{% empty %}
|
||||
<tr><td>{% trans "No domain defined." %}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for template in templates.left %}
|
||||
{% include template %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
{% if user.mailbox %}
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Aliases" %}</h3>
|
||||
</div>
|
||||
<table class="table">
|
||||
{% for alias in user.mailbox.alias_addresses %}
|
||||
<tr><td>{{ alias }}</td></tr>
|
||||
{% empty %}
|
||||
<tr><td>{% trans "No alias defined" %}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for template in templates.right %}
|
||||
{% include template %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends "admin/header.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load admin_tags %}
|
||||
{% load lib_tags %}
|
||||
|
||||
{% block leftcol %}
|
||||
<ul class="nav nav-sidebar">
|
||||
{% identities_menu user "identities" False %}
|
||||
</ul>
|
||||
|
||||
{% get_extra_admin_content user "leftcol" selection %}
|
||||
{% endblock %}
|
||||
|
||||
{% block apparea %}
|
||||
<h2>{% trans "Alias" %} {{ object }}{% if not object.enabled %} <small>{% trans "(disabled)" %}</small>{% endif %}</h2>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Summary" %}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Created" %}</dt><dd>{{ alias.creation|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
<dt>{% trans "Modified" %}</dt><dd>{{ alias.last_modification|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tr><th>{% trans "Recipients" %}</th></tr>
|
||||
{% for recipient in object.recipients %}
|
||||
<tr><td>{{ recipient }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -12,13 +12,13 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block apparea %}
|
||||
<h2>{{ object }} <small>{% trans "Overview" %}</small></h2>
|
||||
<h2>{{ object }} {% if not object.enabled %} <small>{% trans "(disabled)" %}</small>{% endif %}</h2>
|
||||
<hr>
|
||||
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Information" %}</h3>
|
||||
<h3 class="panel-title">{% trans "Summary" %}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
@@ -35,12 +35,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for template in templates.left %}
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-body">
|
||||
{% include template %}
|
||||
</div>
|
||||
{% if object.domainalias_set.exists %}
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Domain aliases" %}</h3>
|
||||
</div>
|
||||
<table class="table">
|
||||
{% for domainalias in object.domainalias_set.all %}
|
||||
<tr><td>{{ domainalias }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for template in templates.left %}
|
||||
{% include template %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -54,7 +63,11 @@
|
||||
<tr>
|
||||
<td>{{ da.username }}</td>
|
||||
<td>{{ da.fullname }}</td>
|
||||
<td name="actions">{% if perms.admin.change_domain %}{% domadmin_actions da.id domain.id %}{% endif %}</td>
|
||||
<td name="actions">
|
||||
{% if perms.admin.change_domain %}
|
||||
<a name="removeperm" href="{% url 'admin:permission_remove' %}?domid={{ domain.id }}&daid={{ da.id }}" title="{% trans 'Remove this permission' %}"><span class="fa fa-trash"></span></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="3">{% trans "No domain administrator defined yet." %}</td></tr>
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{% load i18n admin_tags lib_tags %}
|
||||
|
||||
{% for ident in identities %}
|
||||
{% check_identity_status ident as identity_is_enabled %}
|
||||
<tr id="{{ ident.id }}" class="{% if not identity_is_enabled %}text-muted{% endif %}" name="{{ forloop.counter }}">
|
||||
<td name="identity">{% identity_modify_link ident %}{% if not identity_is_enabled %} (disabled){% endif %}</td>
|
||||
<td name="identity">
|
||||
<a href="{{ ident.get_absolute_url }}">{{ ident }}</a>{% if not identity_is_enabled %} {% trans "(disabled)" %}{% endif %}
|
||||
</td>
|
||||
<td name="name_or_rcpt">{{ ident.name_or_rcpt }}</td>
|
||||
<td name="tags">{% render_tags ident.tags %}</td>
|
||||
<td name="actions">{% identity_actions user ident %}</td>
|
||||
|
||||
@@ -81,24 +81,30 @@ def domains_menu(selection, user, ajax_mode=True):
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def identities_menu(user, selection=None):
|
||||
def identities_menu(user, selection=None, ajax_mode=True):
|
||||
"""Menu specific to the Identities page.
|
||||
|
||||
:param ``User`` user: the connecter user
|
||||
:rtype: str
|
||||
:return: the rendered menu
|
||||
"""
|
||||
if ajax_mode:
|
||||
identity_list_url = "list/"
|
||||
quota_list_url = "quota/"
|
||||
else:
|
||||
identity_list_url = reverse("admin:identity_list")
|
||||
quota_list_url = reverse("admin:quota_list")
|
||||
entries = [
|
||||
{"name": "identities",
|
||||
"label": _("List identities"),
|
||||
"img": "fa fa-user",
|
||||
"class": "ajaxnav navigation",
|
||||
"url": "list/"},
|
||||
"url": identity_list_url},
|
||||
{"name": "quotas",
|
||||
"label": _("List quotas"),
|
||||
"img": "fa fa-hdd-o",
|
||||
"class": "ajaxnav navigation",
|
||||
"url": "quotas/"},
|
||||
"url": quota_list_url},
|
||||
{"name": "newaccount",
|
||||
"label": _("Add account"),
|
||||
"img": "fa fa-plus",
|
||||
@@ -185,7 +191,17 @@ def identity_actions(user, ident):
|
||||
objid = ident.id
|
||||
if name == "User":
|
||||
actions = events.raiseQueryEvent("ExtraAccountActions", ident)
|
||||
url = (
|
||||
reverse("admin:account_change", args=[objid]) +
|
||||
"?active_tab=default"
|
||||
)
|
||||
actions += [
|
||||
{"name": "changeaccount",
|
||||
"url": url,
|
||||
"img": "fa fa-edit",
|
||||
"modal": True,
|
||||
"modalcb": "admin.editaccount_cb",
|
||||
"title": _("Edit {}").format(ident.username)},
|
||||
{"name": "delaccount",
|
||||
"url": reverse("admin:account_delete", args=[objid]),
|
||||
"img": "fa fa-trash",
|
||||
@@ -193,6 +209,12 @@ def identity_actions(user, ident):
|
||||
]
|
||||
else:
|
||||
actions = [
|
||||
{"name": "changealias",
|
||||
"url": reverse("admin:alias_change", args=[objid]),
|
||||
"img": "fa fa-edit",
|
||||
"modal": True,
|
||||
"modalcb": "admin.aliasform_cb",
|
||||
"title": _("Edit {}").format(ident)},
|
||||
{"name": "delalias",
|
||||
"url": "{}?selection={}".format(
|
||||
reverse("admin:alias_delete"), objid),
|
||||
@@ -216,20 +238,6 @@ def check_identity_status(identity):
|
||||
return True
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def domain_modify_link(domain):
|
||||
linkdef = {"label": domain.name, "modal": True}
|
||||
if domain.__class__.__name__ == "Domain":
|
||||
linkdef["url"] = reverse(
|
||||
"admin:domain_change", args=[domain.id])
|
||||
linkdef["modalcb"] = "admin.domainform_cb"
|
||||
else:
|
||||
tmp = events.raiseDictEvent('GetDomainModifyLink', domain)
|
||||
for key in ['url', 'modalcb']:
|
||||
linkdef[key] = tmp[key]
|
||||
return render_link(linkdef)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def domain_aliases(domain):
|
||||
"""Display domain aliases of this domain.
|
||||
|
||||
@@ -37,9 +37,11 @@ urlpatterns += patterns(
|
||||
|
||||
url(r'^accounts/list/$', 'accounts_list', name="account_list"),
|
||||
url(r'^accounts/new/$', 'newaccount', name="account_add"),
|
||||
url(r'^accounts/edit/(?P<accountid>\d+)/$', 'editaccount',
|
||||
url(r'^accounts/(?P<pk>\d+)/$', views.AccountDetailView.as_view(),
|
||||
name="account_detail"),
|
||||
url(r'^accounts/(?P<pk>\d+)/edit/$', 'editaccount',
|
||||
name="account_change"),
|
||||
url(r'^accounts/delete/(?P<accountid>\d+)/$', 'delaccount',
|
||||
url(r'^accounts/(?P<pk>\d+)/delete/$', 'delaccount',
|
||||
name="account_delete"),
|
||||
)
|
||||
|
||||
@@ -50,7 +52,9 @@ urlpatterns += patterns(
|
||||
url(r'^forwards/new/$', 'newforward', name="forward_add"),
|
||||
|
||||
url(r'^aliases/new/$', 'newalias', name="alias_add"),
|
||||
url(r'^aliases/edit/(?P<alid>\d+)/$', 'editalias', name="alias_change"),
|
||||
url(r'^aliases/(?P<pk>\d+)/$', views.AliasDetailView.as_view(),
|
||||
name="alias_detail"),
|
||||
url(r'^aliases/(?P<alid>\d+)/edit/$', 'editalias', name="alias_change"),
|
||||
url(r'^aliases/delete/$', 'delalias', name="alias_delete"),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
"""Shortcuts."""
|
||||
|
||||
from .alias import AliasDetailView
|
||||
from .identity import AccountDetailView
|
||||
from .dnsbl import DNSBLDomainDetailView
|
||||
from .domain import DomainDetailView
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AccountDetailView",
|
||||
"AliasDetailView",
|
||||
"DNSBLDomainDetailView",
|
||||
"DomainDetailView",
|
||||
]
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
"""Alias related views."""
|
||||
|
||||
from django.contrib.auth.decorators import (
|
||||
login_required, permission_required
|
||||
)
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import IntegrityError
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ugettext as _, ungettext
|
||||
from django.views import generic
|
||||
|
||||
from django.contrib.auth import mixins as auth_mixins
|
||||
from django.contrib.auth.decorators import (
|
||||
login_required, permission_required
|
||||
)
|
||||
|
||||
from reversion import revisions as reversion
|
||||
|
||||
@@ -140,3 +143,24 @@ def delalias(request):
|
||||
|
||||
msg = ungettext(msg, msgs, len(selection))
|
||||
return render_to_json_response(msg)
|
||||
|
||||
|
||||
class AliasDetailView(
|
||||
auth_mixins.PermissionRequiredMixin, generic.DetailView):
|
||||
"""DetailView for Alias."""
|
||||
|
||||
model = Alias
|
||||
permission_required = "admin.add_alias"
|
||||
|
||||
def has_permission(self):
|
||||
"""Check object-level access."""
|
||||
result = super(AliasDetailView, self).has_permission()
|
||||
if not result:
|
||||
return result
|
||||
return self.request.user.can_access(self.get_object())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add information to context."""
|
||||
context = super(AliasDetailView, self).get_context_data(**kwargs)
|
||||
context["selection"] = "identities"
|
||||
return context
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
"""Identity related views."""
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ugettext as _, ungettext
|
||||
from django.views import generic
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
|
||||
from django.contrib.auth import mixins as auth_mixins
|
||||
from django.contrib.auth.decorators import (
|
||||
login_required, permission_required, user_passes_test
|
||||
)
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ugettext as _, ungettext
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
|
||||
from reversion import revisions as reversion
|
||||
|
||||
@@ -24,6 +27,7 @@ from modoboa.lib.web_utils import (
|
||||
from ..forms import AccountForm, AccountWizard
|
||||
from ..lib import get_identities
|
||||
from ..models import Mailbox, Domain
|
||||
from .. import signals
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -170,8 +174,8 @@ def newaccount(request):
|
||||
@login_required
|
||||
@permission_required("core.change_user")
|
||||
@reversion.create_revision()
|
||||
def editaccount(request, accountid, tplname="common/tabforms.html"):
|
||||
account = User.objects.get(pk=accountid)
|
||||
def editaccount(request, pk, tplname="common/tabforms.html"):
|
||||
account = User.objects.get(pk=pk)
|
||||
if not request.user.can_access(account):
|
||||
raise PermDeniedException
|
||||
mb = account.mailbox if hasattr(account, "mailbox") else None
|
||||
@@ -208,3 +212,36 @@ def remove_permission(request):
|
||||
raise PermDeniedException
|
||||
domain.remove_admin(account)
|
||||
return render_to_json_response({})
|
||||
|
||||
|
||||
class AccountDetailView(
|
||||
auth_mixins.PermissionRequiredMixin, generic.DetailView):
|
||||
"""DetailView for Account."""
|
||||
|
||||
model = User
|
||||
permission_required = "core.add_user"
|
||||
template_name = "admin/account_detail.html"
|
||||
|
||||
def has_permission(self):
|
||||
"""Check object-level access."""
|
||||
result = super(AccountDetailView, self).has_permission()
|
||||
if not result:
|
||||
return result
|
||||
return self.request.user.can_access(self.get_object())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add information to context."""
|
||||
context = super(AccountDetailView, self).get_context_data(**kwargs)
|
||||
del context["user"]
|
||||
result = signals.extra_account_dashboard_widgets.send(
|
||||
self.__class__, user=self.request.user, account=self.object)
|
||||
context["templates"] = {"left": [], "right": []}
|
||||
for receiver, widgets in result:
|
||||
for widget in widgets:
|
||||
context["templates"][widget["column"]].append(
|
||||
widget["template"])
|
||||
context.update(widget["context"])
|
||||
if self.object.role in ["Resellers", "DomainAdmins"]:
|
||||
context["domains"] = Domain.objects.get_for_admin(self.object)
|
||||
context["selection"] = "identities"
|
||||
return context
|
||||
|
||||
+21
-10
@@ -2,16 +2,18 @@
|
||||
|
||||
import re
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from django.contrib.auth.hashers import make_password, is_password_usable
|
||||
from django.contrib.auth.models import (
|
||||
UserManager, Group, PermissionsMixin
|
||||
)
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
import jsonfield
|
||||
from reversion import revisions as reversion
|
||||
@@ -208,6 +210,10 @@ class User(PermissionsMixin):
|
||||
def has_usable_password(self):
|
||||
return is_password_usable(self.password)
|
||||
|
||||
def get_absolute_url(self):
|
||||
"""Return detail url for this user."""
|
||||
return reverse("admin:account_detail", args=[self.pk])
|
||||
|
||||
@property
|
||||
def tags(self):
|
||||
return [{"name": "account", "label": _("account"), "type": "idt"},
|
||||
@@ -314,12 +320,16 @@ class User(PermissionsMixin):
|
||||
@property
|
||||
def role(self):
|
||||
"""Return user role."""
|
||||
if self.is_superuser:
|
||||
return "SuperAdmins"
|
||||
try:
|
||||
return self.groups.all()[0].name
|
||||
except IndexError:
|
||||
return "---"
|
||||
if not hasattr(self, "_role"):
|
||||
self._role = None
|
||||
if self._role is None:
|
||||
if self.is_superuser:
|
||||
self._role = "SuperAdmins"
|
||||
try:
|
||||
self._role = self.groups.all()[0].name
|
||||
except IndexError:
|
||||
self._role = "---"
|
||||
return self._role
|
||||
|
||||
@role.setter
|
||||
def role(self, role):
|
||||
@@ -345,6 +355,7 @@ class User(PermissionsMixin):
|
||||
from modoboa.lib.permissions import grant_access_to_object
|
||||
grant_access_to_object(self, self)
|
||||
self.save()
|
||||
self._role = role
|
||||
|
||||
def post_create(self, creator):
|
||||
"""Grant permission on this user to creator."""
|
||||
|
||||
@@ -7,6 +7,7 @@ from passlib.hash import bcrypt, md5_crypt, sha256_crypt, sha512_crypt
|
||||
from modoboa.core.password_hashers.base import PasswordHasher
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class BLFCRYPTHasher(PasswordHasher):
|
||||
"""
|
||||
BLF-CRYPT password hasher.
|
||||
@@ -25,7 +26,7 @@ class BLFCRYPTHasher(PasswordHasher):
|
||||
# Using the parameter for rounds will generate the error
|
||||
# ValueError: rounds too high (bcrypt requires <= 31 rounds)
|
||||
# when using the bcrypt hasher.
|
||||
#rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
|
||||
# rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
|
||||
# To get around this, I use the default of 12.
|
||||
rounds = 12
|
||||
return bcrypt.encrypt(clearvalue, rounds=rounds)
|
||||
|
||||
@@ -26,7 +26,6 @@ def core_menu(selection, user):
|
||||
"label": _("Modoboa"),
|
||||
"url": reverse("core:index")}
|
||||
]
|
||||
|
||||
if not len(entries):
|
||||
return ""
|
||||
return render_to_string("common/menulist.html", {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""General event callbacks."""
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from modoboa.lib import events, parameters
|
||||
@@ -10,8 +11,6 @@ from . import utils
|
||||
|
||||
@events.observe("ExtraAdminContent")
|
||||
def display_pool_usage(user, target, currentpage):
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
condition = (
|
||||
parameters.get_admin("ENABLE_ADMIN_LIMITS") == "no" or
|
||||
target != "leftcol" or user.is_superuser)
|
||||
@@ -103,11 +102,12 @@ def fill_account_instances(user, account, instances):
|
||||
|
||||
@events.observe("GetStaticContent")
|
||||
def get_static_content(caller, st_type, user):
|
||||
if parameters.get_admin("ENABLE_ADMIN_LIMITS") == "no":
|
||||
return []
|
||||
if caller not in ['domains', 'identities']:
|
||||
return []
|
||||
if user.group == "SimpleUsers":
|
||||
condition = (
|
||||
parameters.get_admin("ENABLE_ADMIN_LIMITS") == "no" or
|
||||
caller not in ["domains", "identities"] or
|
||||
user.role in ["SuperAdmins", "SimpleUsers"]
|
||||
)
|
||||
if condition:
|
||||
return []
|
||||
if st_type == "css":
|
||||
return ["""<style>
|
||||
|
||||
@@ -76,8 +76,27 @@ def display_domain_limits(sender, user, domain, **kwargs):
|
||||
return []
|
||||
return [{
|
||||
"column": "right",
|
||||
"template": "limits/domain_resources_widget.html",
|
||||
"template": "limits/resources_widget.html",
|
||||
"context": {
|
||||
"limits": domain.domainobjectlimit_set.all()
|
||||
}
|
||||
}]
|
||||
|
||||
|
||||
@receiver(admin_signals.extra_account_dashboard_widgets)
|
||||
def display_admin_limits(sender, user, account, **kwargs):
|
||||
"""Display resources usage for admin."""
|
||||
condition = (
|
||||
parameters.get_admin("ENABLE_ADMIN_LIMITS") == "yes" and
|
||||
account.role in ["DomainAdmins", "Resellers"]
|
||||
)
|
||||
if not condition:
|
||||
return []
|
||||
return [{
|
||||
"column": "right",
|
||||
"template": "limits/resources_widget.html",
|
||||
"context": {
|
||||
"limits": (
|
||||
account.userobjectlimit_set.select_related("content_type"))
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from modoboa.core import models as core_models
|
||||
@@ -60,7 +61,7 @@ class UserObjectLimit(ObjectLimitMixin, models.Model):
|
||||
return tpl
|
||||
return None
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def current_value(self):
|
||||
"""Return the current number of objects."""
|
||||
if "extra_filters" not in self.definition:
|
||||
@@ -79,7 +80,7 @@ class UserObjectLimit(ObjectLimitMixin, models.Model):
|
||||
"""Return display name."""
|
||||
return self.definition["label"]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def usage(self):
|
||||
"""Return current limit usage in %."""
|
||||
if self.max_value < 0:
|
||||
@@ -117,7 +118,7 @@ class DomainObjectLimit(ObjectLimitMixin, models.Model):
|
||||
return tpl
|
||||
return None
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def current_value(self):
|
||||
"""Return the current number of objects."""
|
||||
definition = self.definition
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{% load lib_tags %}
|
||||
|
||||
<div id="{{ id }}" rel="tooltip" title="{{ value }}%" class="progress">
|
||||
<div class="{% progress_color value %}" style="width: {{ value }%"></div>
|
||||
</div>
|
||||
@@ -1,5 +1,7 @@
|
||||
{% extends "common/generic_modal.html" %}
|
||||
|
||||
{% load i18n form_tags %}
|
||||
|
||||
{% block modalbody %}
|
||||
<form id="{{ formid }}" class="form-horizontal" action="{{ action }}" method="POST">{% csrf_token %}
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
|
||||
Reference in New Issue
Block a user