mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: Big refactoring.
This commit is contained in:
+9
-59
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import re
|
||||
import hashlib
|
||||
import crypt
|
||||
@@ -15,6 +16,7 @@ from django.contrib.contenttypes import generic
|
||||
from django.contrib.auth.models import (
|
||||
UserManager, Group, AbstractBaseUser, PermissionsMixin
|
||||
)
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from modoboa.lib import events, md5crypt, parameters
|
||||
from modoboa.lib.exceptions import PermDeniedException
|
||||
from modoboa.core.extensions import exts_pool
|
||||
@@ -43,6 +45,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
is_staff = models.BooleanField(default=False)
|
||||
is_active = models.BooleanField(default=True)
|
||||
date_joined = models.DateTimeField(default=timezone.now)
|
||||
is_local = models.BooleanField(default=True)
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
@@ -90,21 +93,6 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
ungrant_access_to_object(self)
|
||||
super(User, self).delete(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_content_type():
|
||||
"""An uggly hack to retrieve the appropriate content_type!
|
||||
|
||||
The explanation is available here:
|
||||
https://code.djangoproject.com/ticket/11154
|
||||
|
||||
Quickly, the content_types framework does not retrieve the
|
||||
appropriate content type for proxy models, it retrieves the
|
||||
one of the first parent that is not a proxy.
|
||||
"""
|
||||
if not hasattr(User, "ct"):
|
||||
User.ct = ContentType.objects.get(app_label="admin", model="user")
|
||||
return User.ct
|
||||
|
||||
def _crypt_password(self, raw_value):
|
||||
scheme = parameters.get_admin("PASSWORD_SCHEME")
|
||||
if type(raw_value) is unicode:
|
||||
@@ -252,9 +240,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
:param obj: an object inheriting from ``models.Model``
|
||||
:return: a boolean
|
||||
"""
|
||||
from modoboa.lib.permissions import get_content_type
|
||||
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
try:
|
||||
ooentry = self.objectaccess_set.get(content_type=ct, object_id=obj.id)
|
||||
except ObjectAccess.DoesNotExist:
|
||||
@@ -271,12 +257,10 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
:param obj: a admin object
|
||||
:return: a boolean
|
||||
"""
|
||||
from modoboa.lib.permissions import get_content_type
|
||||
|
||||
if self.is_superuser:
|
||||
return True
|
||||
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
try:
|
||||
ooentry = self.objectaccess_set.get(content_type=ct, object_id=obj.id)
|
||||
except ObjectAccess.DoesNotExist:
|
||||
@@ -286,25 +270,13 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
if ct.model == "user":
|
||||
return False
|
||||
|
||||
ct = self.get_content_type()
|
||||
ct = ContentType.objects.get_for_model(self)
|
||||
qs = self.objectaccess_set.filter(content_type=ct)
|
||||
for ooentry in qs.all():
|
||||
if ooentry.content_object.is_owner(obj):
|
||||
return True
|
||||
return False
|
||||
|
||||
def grant_access_to_all_objects(self):
|
||||
"""Give access to all objects defined in the database
|
||||
|
||||
Must be used when an account is promoted as a super user.
|
||||
"""
|
||||
from modoboa.lib.permissions import grant_access_to_objects, get_content_type
|
||||
grant_access_to_objects(self, User.objects.all(), get_content_type(User))
|
||||
grant_access_to_objects(self, Domain.objects.all(), get_content_type(Domain))
|
||||
grant_access_to_objects(self, DomainAlias.objects.all(), get_content_type(DomainAlias))
|
||||
grant_access_to_objects(self, Mailbox.objects.all(), get_content_type(Mailbox))
|
||||
grant_access_to_objects(self, Alias.objects.all(), get_content_type(Alias))
|
||||
|
||||
def set_role(self, role):
|
||||
"""Set administrative role for this account
|
||||
|
||||
@@ -312,10 +284,10 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
"""
|
||||
if role is None or self.group == role:
|
||||
return
|
||||
events.raiseEvent("RoleChanged", self, role)
|
||||
self.groups.clear()
|
||||
if role == "SuperAdmins":
|
||||
self.is_superuser = True
|
||||
self.grant_access_to_all_objects()
|
||||
else:
|
||||
if self.is_superuser:
|
||||
ObjectAccess.objects.filter(user=self).delete()
|
||||
@@ -372,35 +344,13 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||
self.is_active = (row[5].strip() == 'True')
|
||||
self.save(creator=user)
|
||||
self.set_role(role)
|
||||
|
||||
self.email = row[7].strip()
|
||||
if self.email != "":
|
||||
mailbox, domname = split_mailbox(self.email)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise AdminError(
|
||||
_("Account import failed (%s): domain does not exist" % self.username)
|
||||
)
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
mb = Mailbox(address=mailbox, domain=domain, user=self, use_domain_quota=True)
|
||||
mb.set_quota(override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save(creator=user)
|
||||
if self.group == "DomainAdmins":
|
||||
for domname in row[8:]:
|
||||
try:
|
||||
dom = Domain.objects.get(name=domname.strip())
|
||||
except Domain.DoesNotExist:
|
||||
continue
|
||||
dom.add_admin(self)
|
||||
events.raiseEvent("AccountImported", user, self, row[7:])
|
||||
|
||||
def to_csv(self, csvwriter):
|
||||
row = ["account", self.username.encode("utf-8"), self.password,
|
||||
self.first_name.encode("utf-8"), self.last_name.encode("utf-8"),
|
||||
self.is_active, self.group, self.email]
|
||||
if self.group == "DomainAdmins":
|
||||
row += [dom.name for dom in self.get_domains()]
|
||||
row += events.raiseQueryEvent("AccountExported", self)
|
||||
csvwriter.writerow(row)
|
||||
|
||||
reversion.register(User)
|
||||
|
||||
@@ -3,6 +3,36 @@ from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters, events
|
||||
from modoboa.lib.exceptions import PermDeniedException
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.extensions.admin.exceptions import AdminError
|
||||
from modoboa.extensions.admin.models import (
|
||||
Domain, DomainAlias, Mailbox, Alias
|
||||
)
|
||||
|
||||
|
||||
admin_events = [
|
||||
"CreateDomain",
|
||||
"DomainModified",
|
||||
"DeleteDomain",
|
||||
|
||||
"DomainAliasCreated",
|
||||
"DomainAliasDeleted",
|
||||
|
||||
"CreateMailbox",
|
||||
"DeleteMailbox",
|
||||
"ModifyMailbox",
|
||||
|
||||
"MailboxAliasCreated",
|
||||
"MailboxAliasDeleted",
|
||||
|
||||
"ExtraDomainForm",
|
||||
"FillDomainInstances",
|
||||
|
||||
"ExtraAccountForm",
|
||||
"CheckExtraAccountForm",
|
||||
"FillAccountInstances",
|
||||
]
|
||||
|
||||
|
||||
class AdminConsole(ModoExtension):
|
||||
@@ -13,8 +43,9 @@ class AdminConsole(ModoExtension):
|
||||
always_active = True
|
||||
|
||||
def load(self):
|
||||
from app_settings import AdminParametersForm
|
||||
from modoboa.extensions.admin.app_settings import AdminParametersForm
|
||||
parameters.register(AdminParametersForm, ugettext_lazy("Administration"))
|
||||
events.declare(admin_events)
|
||||
|
||||
def destroy(self):
|
||||
parameters.unregister()
|
||||
@@ -25,7 +56,6 @@ exts_pool.register_extension(AdminConsole, show=False)
|
||||
@events.observe("AdminMenuDisplay")
|
||||
def menu(target, user):
|
||||
if target != "top_menu":
|
||||
print "rien"
|
||||
return []
|
||||
entries = []
|
||||
if user.has_perm("admin.view_domains"):
|
||||
@@ -40,5 +70,67 @@ def menu(target, user):
|
||||
"url" : reverse("modoboa.extensions.admin.views.identity.identities"),
|
||||
"label" : _("Identities")},
|
||||
]
|
||||
print entries
|
||||
return entries
|
||||
|
||||
|
||||
@events.observe("RoleChanged")
|
||||
def grant_access_to_all_objects(user, role):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from modoboa.lib.permissions import grant_access_to_objects
|
||||
from modoboa.core.models import User
|
||||
|
||||
if role != "SuperAdmins":
|
||||
return
|
||||
grant_access_to_objects(
|
||||
user, User.objects.all(),
|
||||
ContentType.objects.get_for_model(User)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Domain.objects.all(),
|
||||
ContentType.objects.get_for_model(Domain)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, DomainAlias.objects.all(),
|
||||
ContentType.objects.get_for_model(DomainAlias)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Mailbox.objects.all(),
|
||||
ContentType.objects.get_for_model(Mailbox)
|
||||
)
|
||||
grant_access_to_objects(
|
||||
user, Alias.objects.all(),
|
||||
ContentType.objects.get_for_model(Alias)
|
||||
)
|
||||
|
||||
|
||||
@events.observe("AccountExported")
|
||||
def export_admin_domains(admin):
|
||||
if admin.group != "DomainAdmins":
|
||||
return []
|
||||
return [dom.name for dom in Domain.objects.get_for_admin(admin)]
|
||||
|
||||
|
||||
@events.observe("AccountImported")
|
||||
def import_account_mailbox(user, account, row):
|
||||
account.email = row[0].strip()
|
||||
if account.email != "":
|
||||
mailbox, domname = split_mailbox(account.email)
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
except Domain.DoesNotExist:
|
||||
raise AdminError(
|
||||
_("Account import failed (%s): domain does not exist" % account.username)
|
||||
)
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
mb = Mailbox(address=mailbox, domain=domain,
|
||||
user=account, use_domain_quota=True)
|
||||
mb.set_quota(override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save(creator=user)
|
||||
if account.group == "DomainAdmins":
|
||||
for domname in row[1:]:
|
||||
try:
|
||||
dom = Domain.objects.get(name=domname.strip())
|
||||
except Domain.DoesNotExist:
|
||||
continue
|
||||
dom.add_admin(account)
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"pk": 1, "model": "auth.group", "fields": {"name": "DomainAdmins", "permissions": [["add_user", "admin", "user"], ["change_user", "admin", "user"], ["delete_user", "admin", "user"], ["view_domains", "admin", "domain"], ["add_mailbox", "admin", "mailbox"], ["change_mailbox", "admin", "mailbox"], ["delete_mailbox", "admin", "mailbox"], ["add_alias", "admin", "alias"], ["change_alias", "admin", "alias"], ["delete_alias", "admin", "alias"], ["view_mailboxes", "admin", "mailbox"], ["view_aliases", "admin", "alias"], ["view_domaliases", "admin", "domainalias"], ["add_domainalias", "admin", "domainalias"], ["change_domainalias", "admin", "domainalias"], ["delete_domainalias", "admin", "domainalias"]]}},{"pk": 2, "model": "auth.group", "fields": {"name": "SimpleUsers", "permissions": []}}]
|
||||
[{"pk": 1, "model": "auth.group", "fields": {"name": "DomainAdmins", "permissions": [["add_user", "core", "user"], ["change_user", "core", "user"], ["delete_user", "core", "user"], ["view_domains", "admin", "domain"], ["add_mailbox", "admin", "mailbox"], ["change_mailbox", "admin", "mailbox"], ["delete_mailbox", "admin", "mailbox"], ["add_alias", "admin", "alias"], ["change_alias", "admin", "alias"], ["delete_alias", "admin", "alias"], ["view_mailboxes", "admin", "mailbox"], ["view_aliases", "admin", "alias"], ["view_domaliases", "admin", "domainalias"], ["add_domainalias", "admin", "domainalias"], ["change_domainalias", "admin", "domainalias"], ["delete_domainalias", "admin", "domainalias"]]}},{"pk": 2, "model": "auth.group", "fields": {"name": "SimpleUsers", "permissions": []}}]
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"pk": 1, "model": "admin.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "last_login": "2012-01-26 15:19:25", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26 15:19:25"}},{"pk": 1, "model": "admin.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["admin", "user"], "object_id": 1}}]
|
||||
[{"pk": 1, "model": "core.user", "fields": {"username": "admin", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": false, "is_local": true, "last_login": "2012-01-26 15:19:25", "groups": [], "user_permissions": [], "password": "{CRYPT}dTTsGDkA5ZHKg", "email": "", "date_joined": "2012-01-26 15:19:25"}},{"pk": 1, "model": "core.objectaccess", "fields": {"is_owner": true, "user": 1, "content_type": ["core", "user"], "object_id": 1}}]
|
||||
@@ -1,6 +1,11 @@
|
||||
# coding: utf-8
|
||||
from django.db.models import Q
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from modoboa.core.models import User
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.emailutils import split_mailbox
|
||||
from modoboa.extensions.admin.models import Alias
|
||||
|
||||
|
||||
def get_sort_order(qdict, default, allowed_values=None):
|
||||
@@ -23,9 +28,71 @@ def get_sort_order(qdict, default, allowed_values=None):
|
||||
|
||||
|
||||
def get_listing_page(objects, pagenum):
|
||||
paginator = Paginator(objects, int(parameters.get_admin("ITEMS_PER_PAGE")))
|
||||
paginator = Paginator(
|
||||
objects, int(parameters.get_admin("ITEMS_PER_PAGE", app="core"))
|
||||
)
|
||||
try:
|
||||
page = paginator.page(int(pagenum))
|
||||
except (EmptyPage, PageNotAnInteger, ValueError):
|
||||
page = paginator.page(paginator.num_pages)
|
||||
return page
|
||||
|
||||
|
||||
def get_identities(user, args=None):
|
||||
"""Return all the identities owned by a user
|
||||
|
||||
:param user: the desired user
|
||||
:param args: a args object
|
||||
:return: a queryset
|
||||
"""
|
||||
from itertools import chain
|
||||
|
||||
if args:
|
||||
squery = args.get("searchquery", None)
|
||||
idtfilter = args.getlist("idtfilter", None)
|
||||
grpfilter = args.getlist("grpfilter", None)
|
||||
else:
|
||||
squery = None
|
||||
idtfilter = None
|
||||
grpfilter = None
|
||||
|
||||
accounts = []
|
||||
if not idtfilter or "account" in idtfilter:
|
||||
ids = user.objectaccess_set \
|
||||
.filter(content_type=ContentType.objects.get_for_model(user)) \
|
||||
.values_list('object_id', flat=True)
|
||||
q = Q(pk__in=ids)
|
||||
if squery:
|
||||
q &= Q(username__icontains=squery) | Q(email__icontains=squery)
|
||||
if grpfilter and len(grpfilter):
|
||||
if "SuperAdmins" in grpfilter:
|
||||
q &= Q(is_superuser=True)
|
||||
grpfilter.remove("SuperAdmins")
|
||||
if len(grpfilter):
|
||||
q |= Q(groups__name__in=grpfilter)
|
||||
else:
|
||||
q &= Q(groups__name__in=grpfilter)
|
||||
accounts = User.objects.select_related().filter(q)
|
||||
|
||||
aliases = []
|
||||
if not idtfilter or ("alias" in idtfilter
|
||||
or "forward" in idtfilter
|
||||
or "dlist" in idtfilter):
|
||||
alct = ContentType.objects.get_for_model(Alias)
|
||||
ids = user.objectaccess_set.filter(content_type=alct) \
|
||||
.values_list('object_id', flat=True)
|
||||
q = Q(pk__in=ids)
|
||||
if squery:
|
||||
if '@' in squery:
|
||||
local_part, domname = split_mailbox(squery)
|
||||
if local_part:
|
||||
q &= Q(address__icontains=local_part)
|
||||
if domname:
|
||||
q &= Q(domain__name__icontains=domname)
|
||||
else:
|
||||
q &= Q(address__icontains=squery) | Q(domain__name__icontains=squery)
|
||||
aliases = Alias.objects.select_related().filter(q)
|
||||
if idtfilter:
|
||||
aliases = [al for al in aliases if al.type in idtfilter]
|
||||
|
||||
return chain(accounts, aliases)
|
||||
|
||||
@@ -142,7 +142,7 @@ class Migration(SchemaMigration):
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
user_model_name: {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'Meta': {'object_name': 'User', 'db_table': "'admin_user'"},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
|
||||
@@ -149,7 +149,7 @@ class Migration(DataMigration):
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
user_model_name: {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'Meta': {'object_name': 'User', 'db_table': "'admin_user'"},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
|
||||
@@ -93,7 +93,7 @@ class Migration(SchemaMigration):
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
user_model_name: {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'Meta': {'object_name': 'User', 'db_table': "'admin_user'"},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
|
||||
@@ -98,7 +98,7 @@ class Migration(DataMigration):
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
user_model_name: {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'Meta': {'object_name': 'User', 'db_table': "'admin_user'"},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
|
||||
@@ -97,7 +97,7 @@ class Migration(DataMigration):
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
user_model_name: {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'Meta': {'object_name': 'User', 'db_table': "'admin_user'"},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
|
||||
@@ -36,6 +36,7 @@ class Alias(DatesAware):
|
||||
)
|
||||
unique_together = (("address", "domain"),)
|
||||
ordering = ["domain__name", "address"]
|
||||
app_label = 'admin'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.full_address
|
||||
|
||||
@@ -10,6 +10,9 @@ class ObjectDates(models.Model):
|
||||
creation = models.DateTimeField(auto_now_add=True)
|
||||
last_modification = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'admin'
|
||||
|
||||
@staticmethod
|
||||
def set_for_object(obj):
|
||||
"""Initialize or update dates for a given object.
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
import reversion
|
||||
from django.db import models
|
||||
from django.db.models.manager import Manager
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.contrib.contenttypes import generic
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.core.models import ObjectAccess
|
||||
from modoboa.extensions.admin.exceptions import AdminError
|
||||
from .base import DatesAware
|
||||
|
||||
|
||||
class DomainManager(Manager):
|
||||
|
||||
def get_for_admin(self, admin):
|
||||
"""Return the domains belonging to this admin
|
||||
|
||||
The result is a ``QuerySet`` object, so this function can be used
|
||||
to fill ``ModelChoiceField`` objects.
|
||||
"""
|
||||
if admin.is_superuser:
|
||||
return self.get_query_set()
|
||||
return self.get_query_set().filter(owners__user=admin)
|
||||
|
||||
|
||||
class Domain(DatesAware):
|
||||
name = models.CharField(ugettext_lazy('name'), max_length=100, unique=True,
|
||||
help_text=ugettext_lazy("The domain name"))
|
||||
@@ -19,12 +34,15 @@ class Domain(DatesAware):
|
||||
)
|
||||
owners = generic.GenericRelation(ObjectAccess)
|
||||
|
||||
objects = DomainManager()
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_domain", "View domain"),
|
||||
("view_domains", "View domains"),
|
||||
)
|
||||
ordering = ["name"]
|
||||
app_label = 'admin'
|
||||
|
||||
@property
|
||||
def domainalias_count(self):
|
||||
@@ -79,6 +97,7 @@ class Domain(DatesAware):
|
||||
def delete(self, fromuser, keepdir=False):
|
||||
from modoboa.lib.permissions import \
|
||||
ungrant_access_to_object, ungrant_access_to_objects
|
||||
from .mailbox import Quota
|
||||
|
||||
if self.domainalias_set.count():
|
||||
events.raiseEvent("DomainAliasDeleted", self.domainalias_set.all())
|
||||
@@ -123,7 +142,10 @@ class Domain(DatesAware):
|
||||
if len(row) < 4:
|
||||
raise AdminError(_("Invalid line"))
|
||||
self.name = row[1].strip()
|
||||
self.quota = int(row[2].strip())
|
||||
try:
|
||||
self.quota = int(row[2].strip())
|
||||
except ValueError:
|
||||
raise AdminError(_("Invalid quota value for domain '%s'" % self.name))
|
||||
self.enabled = (row[3].strip() == 'True')
|
||||
self.save(creator=user)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class DomainAlias(DatesAware):
|
||||
permissions = (
|
||||
("view_domaliases", "View domain aliases"),
|
||||
)
|
||||
app_label = 'admin'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import os
|
||||
import reversion
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models.manager import Manager
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.db.models.signals import pre_delete
|
||||
from django.dispatch import receiver
|
||||
@@ -12,6 +15,36 @@ from .base import DatesAware
|
||||
from .domain import Domain
|
||||
|
||||
|
||||
class MailboxManager(Manager):
|
||||
|
||||
def get_for_admin(self, admin, squery=None):
|
||||
"""Return the mailboxes that belong to this admin.
|
||||
|
||||
The result will contain the mailboxes defined for each domain that
|
||||
user can see.
|
||||
|
||||
:param string squery: a search query
|
||||
:return: a list of ``Mailbox`` objects
|
||||
"""
|
||||
qf = None
|
||||
if squery is not None:
|
||||
if '@' in squery:
|
||||
parts = squery.split('@')
|
||||
addrfilter = '@'.join(parts[:-1])
|
||||
domfilter = parts[-1]
|
||||
qf = Q(address__contains=addrfilter) & Q(domain__name__contains=domfilter)
|
||||
else:
|
||||
qf = Q(address__contains=squery) | Q(domain__name__contains=squery)
|
||||
ids = admin.objectaccess_set \
|
||||
.filter(content_type=ContentType.objects.get_for_model(Mailbox)) \
|
||||
.values_list('object_id', flat=True)
|
||||
if qf is not None:
|
||||
qf = Q(pk__in=ids) & qf
|
||||
else:
|
||||
qf = Q(pk__in=ids)
|
||||
return self.get_query_set().filter(qf)
|
||||
|
||||
|
||||
class Mailbox(DatesAware):
|
||||
address = models.CharField(
|
||||
ugettext_lazy('address'), max_length=252,
|
||||
@@ -22,10 +55,13 @@ class Mailbox(DatesAware):
|
||||
domain = models.ForeignKey(Domain)
|
||||
user = models.ForeignKey(User)
|
||||
|
||||
objects = MailboxManager()
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_mailboxes", "View mailboxes"),
|
||||
)
|
||||
app_label = 'admin'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Mailbox, self).__init__(*args, **kwargs)
|
||||
@@ -211,3 +247,6 @@ class Quota(models.Model):
|
||||
messages = models.IntegerField(default=0)
|
||||
|
||||
mbox = models.OneToOneField(Mailbox, related_name="quota_value", null=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'admin'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "common/tabforms.html" %}{% load i18n libextras admin_extras %}
|
||||
{% extends "common/tabforms.html" %}{% load i18n libextras admin_tags %}
|
||||
{% block extratabs %}
|
||||
<li class="{% if tabs.active_id == 'admins' %}active{% endif %}">
|
||||
<a href="#admins" data-toggle="tab">{% trans "Administrators" %}</a>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load i18n admin_extras libextras %}
|
||||
{% load i18n admin_tags libextras %}
|
||||
<table id="{{ tableid }}" class="table {{ styles }}">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{% load i18n admin_extras %}
|
||||
<h2>{% trans "Logs" %} <small>{% trans "Previously on Modoboa..." %}</small></h2><hr>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable" data-sort_order="date_created" width="20%">{% trans "Date" %}</th>
|
||||
<th class="sortable" data-sort_order="level" width="7%">{% trans "Level" %}</th>
|
||||
<th class="sortable" data-sort_order="logger" width="15%">{% trans "Logger" %}</th>
|
||||
<th class="sortable" data-sort_order="message" width="">{% trans "Message" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for l in logs %}<tr>
|
||||
<td>{{ l.date_created }}</td>
|
||||
<td>{{ l.level|colorize_level|safe }}</td>
|
||||
<td>{{ l.logger }}</td>
|
||||
<td>{{ l.message|tohtml|safe }}</td>
|
||||
</tr>{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load i18n libextras admin_extras %}
|
||||
{% load i18n libextras admin_tags %}
|
||||
<table class="table table-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{% extends "twocols.html" %}
|
||||
{% load i18n libextras admin_extras %}
|
||||
{% block pagetitle %}{% trans "Modoboa settings" %}{% endblock %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/settings.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/jquery.sortable.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/listing.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/twocols_nav.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.sortable.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var settings = new TwocolsNav({
|
||||
deflocation: "parameters/",
|
||||
formid: "settings_form",
|
||||
divid: "settings_content",
|
||||
reload_exceptions: ["extensions"]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block leftcol %}<div class="well sidebar-nav">{% settings_menu left_selection user %}</div>{% endblock %}
|
||||
{% block apparea %}<div id="settings_content"></div>{% endblock %}
|
||||
@@ -106,19 +106,19 @@ def identities_menu(user):
|
||||
|
||||
@register.simple_tag
|
||||
def domain_actions(user, domid):
|
||||
from modoboa.admin.models import Domain
|
||||
from modoboa.extensions.admin.models import Domain
|
||||
|
||||
domain = Domain.objects.get(pk=domid)
|
||||
actions = [
|
||||
{"name": "listidentities",
|
||||
"url": reverse("modoboa.admin.views.identities") + "#list/?searchquery=@%s" % domain.name,
|
||||
"url": reverse("modoboa.extensions.admin.views.identity.identities") + "#list/?searchquery=@%s" % domain.name,
|
||||
"title": _("View the domain's identities"),
|
||||
"img": "icon-user"}
|
||||
]
|
||||
if user.has_perm("admin.delete_domain"):
|
||||
actions.append({
|
||||
"name": "deldomain",
|
||||
"url": reverse("modoboa.admin.views.deldomain", args=[domid]),
|
||||
"url": reverse("modoboa.extensions.admin.views.domain.deldomain", args=[domid]),
|
||||
"title": _("Delete the domain"),
|
||||
"img": "icon-trash"
|
||||
})
|
||||
@@ -132,72 +132,78 @@ def identity_actions(user, ident):
|
||||
if name == "User":
|
||||
actions = events.raiseQueryEvent("ExtraAccountActions", ident)
|
||||
actions += [
|
||||
{"name" : "delaccount",
|
||||
"url" : reverse("modoboa.admin.views.delaccount", args=[objid]),
|
||||
"img" : "icon-trash",
|
||||
"title" : _("Delete this account")},
|
||||
]
|
||||
{"name": "delaccount",
|
||||
"url": reverse("modoboa.extensions.admin.views.identity.delaccount", args=[objid]),
|
||||
"img": "icon-trash",
|
||||
"title": _("Delete this account")},
|
||||
]
|
||||
else:
|
||||
if ident.get_recipients_count() >= 2:
|
||||
actions = [
|
||||
{"name" : "deldlist",
|
||||
"url" : reverse("modoboa.admin.views.deldlist") + "?selection=%s" % objid,
|
||||
"img" : "icon-trash",
|
||||
"title" : _("Delete this distribution list")},
|
||||
]
|
||||
{"name": "deldlist",
|
||||
"url": reverse("modoboa.extensions.admin.views.alias.deldlist") + "?selection=%s" % objid,
|
||||
"img": "icon-trash",
|
||||
"title": _("Delete this distribution list")},
|
||||
]
|
||||
elif ident.extmboxes != "":
|
||||
actions = [
|
||||
{"name" : "delforward",
|
||||
"url" : reverse("modoboa.admin.views.delforward") + "?selection=%s" % objid,
|
||||
"img" : "icon-trash",
|
||||
"title" : _("Delete this forward")},
|
||||
]
|
||||
{"name": "delforward",
|
||||
"url": reverse("modoboa.extensions.admin.views.alias.delforward") + "?selection=%s" % objid,
|
||||
"img": "icon-trash",
|
||||
"title": _("Delete this forward")},
|
||||
]
|
||||
else:
|
||||
actions = [
|
||||
{"name" : "delalias",
|
||||
"url" : reverse("modoboa.admin.views.delalias") + "?selection=%s" % objid,
|
||||
"img" : "icon-trash",
|
||||
"title" : _("Delete this alias")},
|
||||
]
|
||||
{"name": "delalias",
|
||||
"url": reverse("modoboa.extensions.admin.views.alias.delalias") + "?selection=%s" % objid,
|
||||
"img": "icon-trash",
|
||||
"title": _("Delete this alias")},
|
||||
]
|
||||
return render_actions(actions)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def identity_modify_link(identity, active_tab='default'):
|
||||
linkdef = {"label" : identity.identity, "modal" : True}
|
||||
linkdef = {"label": identity.identity, "modal": True}
|
||||
if identity.__class__.__name__ == "User":
|
||||
linkdef["url"] = reverse("modoboa.admin.views.editaccount", args=[identity.id])
|
||||
linkdef["url"] = reverse(
|
||||
"modoboa.extensions.admin.views.identity.editaccount",
|
||||
args=[identity.id]
|
||||
)
|
||||
linkdef["url"] += "?active_tab=%s" % active_tab
|
||||
linkdef["modalcb"] = "admin.editaccount_cb"
|
||||
else:
|
||||
linkdef["url"] = reverse("modoboa.admin.views.editalias", args=[identity.id])
|
||||
linkdef["url"] = reverse(
|
||||
"modoboa.extensions.admin.views.alias.editalias",
|
||||
args=[identity.id]
|
||||
)
|
||||
linkdef["modalcb"] = "admin.aliasform_cb"
|
||||
return render_link(linkdef)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def domadmin_actions(daid, domid):
|
||||
actions = [dict(
|
||||
name="removeperm",
|
||||
url=reverse("modoboa.admin.views.remove_permission") + "?domid=%s&daid=%s" % (domid, daid),
|
||||
img="icon-trash",
|
||||
title=_("Remove this permission")
|
||||
)]
|
||||
actions = [{
|
||||
"name": "removeperm",
|
||||
"url": reverse("modoboa.extensions.admin.views.identity.remove_permission") + "?domid=%s&daid=%s" % (domid, daid),
|
||||
"img": "icon-trash",
|
||||
"title": _("Remove this permission")
|
||||
}]
|
||||
return render_actions(actions)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def loadadminextmenu(user):
|
||||
menu = events.raiseQueryEvent("AdminMenuDisplay", "admin_menu_box", user)
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries" : menu, "user" : user})
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries": menu, "user": user})
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def param(app, definition):
|
||||
name = "%s.%s" % (app, definition["name"])
|
||||
value = definition.has_key("value") \
|
||||
and definition["value"] or definition["deflt"]
|
||||
value = definition["value"] \
|
||||
if "value" in definition else definition["deflt"]
|
||||
|
||||
if definition["type"] == "separator":
|
||||
return "<h5>%s</h5>" % (unicode(definition["label"]))
|
||||
@@ -211,8 +217,7 @@ def param(app, definition):
|
||||
result = """<div class='control-group'%s>
|
||||
<label class="param-label" for="%s">%s</label>
|
||||
""" % (extratags, name,
|
||||
definition.has_key("label") and _(definition["label"])
|
||||
or definition["name"])
|
||||
_(definition["label"]) if "label" in definition else definition["name"])
|
||||
|
||||
result += "<div class='param-controls'>"
|
||||
if definition["type"] in ["string", "int"]:
|
||||
@@ -222,7 +227,7 @@ def param(app, definition):
|
||||
if definition["type"] == "text":
|
||||
result += "<textarea name='%s' id='%s'>%s</textarea>" \
|
||||
% (name, name, value)
|
||||
|
||||
|
||||
if definition["type"] == "list_yesno":
|
||||
for idx, v in enumerate([("yes", _("Yes")), ("no", _("No"))]):
|
||||
checked = "checked" if value == v[0] else ""
|
||||
@@ -230,13 +235,14 @@ def param(app, definition):
|
||||
<input type="radio" name="%(name)s" id="%(id)s" value="%(value)s"%(checked)s />
|
||||
%(label)s
|
||||
</label>
|
||||
""" % dict(id="%s_%d" % (name, idx), name=name, value=v[0], label=v[1], checked=checked)
|
||||
""" % dict(id="%s_%d" % (name, idx), name=name, value=v[0],
|
||||
label=v[1], checked=checked)
|
||||
|
||||
if definition["type"] == "list":
|
||||
result += """
|
||||
<select name='%s' id='%s'>""" % (name, name)
|
||||
values = []
|
||||
if definition.has_key("values"):
|
||||
if "values" in definition:
|
||||
values = definition["values"]
|
||||
for v in values:
|
||||
selected = ""
|
||||
@@ -247,7 +253,7 @@ def param(app, definition):
|
||||
</select>
|
||||
"""
|
||||
|
||||
if definition.has_key("help"):
|
||||
if "help" in definition:
|
||||
result += """<a class="help" rel="popover" data-content="%s" data-original-title="%s">
|
||||
<i class="icon-info-sign"></i>
|
||||
</a>""" % (unicode(definition["help"]), _("Help"))
|
||||
@@ -264,7 +270,7 @@ def param(app, definition):
|
||||
|
||||
@register.filter
|
||||
def gender(value, target):
|
||||
if genders.has_key(value):
|
||||
if value in genders:
|
||||
trans = target == "m" and genders[value][0] or genders[value][1]
|
||||
if trans.find("_") == -1:
|
||||
return trans
|
||||
@@ -273,5 +279,7 @@ def gender(value, target):
|
||||
|
||||
@register.simple_tag
|
||||
def get_extra_admin_content(user, target, currentpage):
|
||||
res = events.raiseQueryEvent("ExtraAdminContent", user, target, currentpage)
|
||||
res = events.raiseQueryEvent(
|
||||
"ExtraAdminContent", user, target, currentpage
|
||||
)
|
||||
return "".join(res)
|
||||
|
||||
@@ -15,10 +15,10 @@ from django.test.client import Client
|
||||
from django.utils import simplejson
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.files.base import ContentFile
|
||||
from models import *
|
||||
from modoboa.admin.lib import *
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
from modoboa.extensions.admin.lib import *
|
||||
from modoboa.extensions.admin.models import *
|
||||
|
||||
|
||||
class DomainTestCase(ModoTestCase):
|
||||
|
||||
@@ -3,6 +3,7 @@ from django.conf.urls import patterns, url
|
||||
|
||||
urlpatterns = patterns(
|
||||
'modoboa.extensions.admin.views.domain',
|
||||
(r'^$', 'index'),
|
||||
url(r'^domains/$', 'domains', name="domains"),
|
||||
(r'^domains/list/$', '_domains'),
|
||||
(r'^domains/flatlist/$', 'domains_list'),
|
||||
|
||||
@@ -22,13 +22,18 @@ from modoboa.extensions.admin.forms import (
|
||||
)
|
||||
|
||||
|
||||
@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()
|
||||
domains = Domain.objects.get_for_admin(request.user)
|
||||
squery = request.GET.get("searchquery", None)
|
||||
if squery is not None:
|
||||
q = Q(name__contains=squery)
|
||||
@@ -60,7 +65,7 @@ def domains(request, tplname="admin/domains.html"):
|
||||
@login_required
|
||||
@permission_required("admin.add_user")
|
||||
def domains_list(request):
|
||||
doms = [dom.name for dom in request.user.get_domains()]
|
||||
doms = [dom.name for dom in Domain.objects.get_for_admin(request.user)]
|
||||
return ajax_simple_response(doms)
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ from django.utils.translation import ugettext as _, ungettext
|
||||
from django.contrib.auth.decorators import (
|
||||
login_required, permission_required, user_passes_test
|
||||
)
|
||||
from modoboa.extensions.admin.lib import get_identities
|
||||
from modoboa.extensions.admin.models import Domain
|
||||
from modoboa.extensions.admin.forms import (
|
||||
ExportIdentitiesForm, ExportDomainsForm
|
||||
)
|
||||
@@ -45,7 +47,7 @@ def export_identities(request):
|
||||
form.is_valid()
|
||||
fp = cStringIO.StringIO()
|
||||
csvwriter = csv.writer(fp, delimiter=form.cleaned_data["sepchar"])
|
||||
for ident in request.user.get_identities():
|
||||
for ident in get_identities(request.user):
|
||||
ident.to_csv(csvwriter)
|
||||
content = fp.getvalue()
|
||||
fp.close()
|
||||
@@ -71,7 +73,7 @@ def export_domains(request):
|
||||
form.is_valid()
|
||||
fp = cStringIO.StringIO()
|
||||
csvwriter = csv.writer(fp, delimiter=form.cleaned_data["sepchar"])
|
||||
for dom in request.user.get_domains():
|
||||
for dom in Domain.objects.get_for_admin(request.user):
|
||||
dom.to_csv(csvwriter)
|
||||
for da in dom.domainalias_set.all():
|
||||
da.to_csv(csvwriter)
|
||||
|
||||
@@ -12,7 +12,10 @@ from modoboa.lib.webutils import ajax_simple_response, _render_to_string
|
||||
from modoboa.lib.formutils import CreationWizard
|
||||
from modoboa.lib.templatetags.libextras import pagination_bar
|
||||
from modoboa.core.models import User
|
||||
from modoboa.extensions.admin.lib import get_sort_order, get_listing_page
|
||||
from modoboa.extensions.admin.models import Mailbox
|
||||
from modoboa.extensions.admin.lib import (
|
||||
get_sort_order, get_listing_page, get_identities
|
||||
)
|
||||
from modoboa.extensions.admin.exceptions import AdminError
|
||||
from modoboa.extensions.admin.forms import (
|
||||
AccountForm, AccountFormGeneral, AccountFormMail
|
||||
@@ -24,7 +27,7 @@ from modoboa.extensions.admin.forms import (
|
||||
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)
|
||||
idents_list = get_identities(request.user, request.GET)
|
||||
sort_order, sort_dir = get_sort_order(request.GET, "identity",
|
||||
["identity", "name_or_rcpt", "tags"])
|
||||
if sort_order in ["identity", "name_or_rcpt"]:
|
||||
@@ -73,7 +76,9 @@ def list_quotas(request, tplname="admin/quotas.html"):
|
||||
from modoboa.lib.dbutils import db_type
|
||||
|
||||
sort_order, sort_dir = get_sort_order(request.GET, "address")
|
||||
mboxes = request.user.get_mailboxes(request.GET.get("searchquery", None))
|
||||
mboxes = Mailbox.objects.get_for_admin(
|
||||
request.user, request.GET.get("searchquery", None)
|
||||
)
|
||||
mboxes = mboxes.exclude(quota=0)
|
||||
if sort_order in ["address", "quota", "quota_value__bytes"]:
|
||||
mboxes = mboxes.order_by("%s%s" % (sort_dir, sort_order))
|
||||
@@ -175,7 +180,7 @@ def editaccount(request, accountid, tplname="common/tabforms.html"):
|
||||
if not request.user.can_access(account):
|
||||
raise PermDeniedException
|
||||
mb = None
|
||||
if account.has_mailbox:
|
||||
if account.mailbox_set.count():
|
||||
mb = account.mailbox_set.all()[0]
|
||||
|
||||
instances = dict(general=account, mail=mb, perms=account)
|
||||
|
||||
@@ -5,7 +5,7 @@ from django.forms.widgets import RadioFieldRenderer, RadioSelect, RadioInput
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.html import conditional_escape
|
||||
from django.utils.encoding import force_unicode
|
||||
from modoboa.admin.templatetags.admin_extras import gender
|
||||
from modoboa.extensions.admin.templatetags.admin_tags import gender
|
||||
|
||||
class FiltersSetForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
|
||||
@@ -22,7 +22,7 @@ class Stats(ModoExtension):
|
||||
|
||||
def load(self):
|
||||
from app_settings import ParametersForm
|
||||
events.registerEvent("GetGraphSets")
|
||||
events.declare(["GetGraphSets"])
|
||||
parameters.register(ParametersForm, ugettext_lazy("Graphical statistics"))
|
||||
|
||||
def destroy(self):
|
||||
|
||||
+31
-42
@@ -16,47 +16,27 @@ from django.conf import settings
|
||||
events = [
|
||||
"CanCreate",
|
||||
|
||||
"CreateDomain",
|
||||
"DomainModified",
|
||||
"DeleteDomain",
|
||||
|
||||
"DomainAliasCreated",
|
||||
"DomainAliasDeleted",
|
||||
|
||||
"CreateMailbox",
|
||||
"DeleteMailbox",
|
||||
"ModifyMailbox",
|
||||
|
||||
"MailboxAliasCreated",
|
||||
"MailboxAliasDeleted",
|
||||
|
||||
"AccountCreated",
|
||||
"AccountModified",
|
||||
"AccountDeleted",
|
||||
"AccountExported",
|
||||
"AccountImported",
|
||||
"PasswordUpdated",
|
||||
"ExtraAccountActions",
|
||||
|
||||
"RoleChanged",
|
||||
"GetExtraRoles",
|
||||
"PasswordChange",
|
||||
|
||||
|
||||
"UserMenuDisplay",
|
||||
"AdminMenuDisplay",
|
||||
"GetStaticContent",
|
||||
|
||||
"ExtraAccountForm",
|
||||
"CheckExtraAccountForm",
|
||||
"FillAccountInstances",
|
||||
|
||||
"ExtraDomainForm",
|
||||
"FillDomainInstances",
|
||||
|
||||
"GetExtraRoles",
|
||||
|
||||
"ExtEnabled",
|
||||
"ExtDisabled",
|
||||
|
||||
"UserLogin",
|
||||
"UserLogout",
|
||||
|
||||
|
||||
"GetAnnouncement",
|
||||
|
||||
"TopNotifications",
|
||||
@@ -64,17 +44,20 @@ events = [
|
||||
|
||||
"ExtraUprefsRoutes",
|
||||
"ExtraUprefsJS"
|
||||
]
|
||||
]
|
||||
|
||||
callbacks = {}
|
||||
|
||||
def registerEvent(name):
|
||||
"""Register a new event
|
||||
|
||||
:param name: the event's name
|
||||
def declare(nevents):
|
||||
"""Declare new events
|
||||
|
||||
:param list nevents: a list of event names
|
||||
"""
|
||||
if not name in events:
|
||||
events.append(name)
|
||||
for evt in nevents:
|
||||
if not evt in events:
|
||||
events.append(evt)
|
||||
|
||||
|
||||
def register(event, callback):
|
||||
"""Register a plugin callback for a specific event
|
||||
@@ -90,10 +73,11 @@ def register(event, callback):
|
||||
if not event in callbacks.keys():
|
||||
callbacks[event] = {}
|
||||
fullname = "%s.%s" % (callback.__module__, callback.__name__)
|
||||
if not callbacks[event].has_key(fullname):
|
||||
if not fullname in callbacks[event]:
|
||||
callbacks[event][fullname] = callback
|
||||
return 1
|
||||
|
||||
|
||||
class observe(object):
|
||||
"""Event observing decorator
|
||||
|
||||
@@ -111,7 +95,7 @@ class observe(object):
|
||||
"""
|
||||
def __init__(self, *evtnames, **kwargs):
|
||||
self.evtnames = evtnames
|
||||
if kwargs.has_key("extname"):
|
||||
if "extname" in kwargs:
|
||||
self.extname = kwargs["extname"]
|
||||
|
||||
def __guess_extension_name(self, modname):
|
||||
@@ -123,7 +107,9 @@ class observe(object):
|
||||
|
||||
def __call__(self, f):
|
||||
modname = inspect.getmodule(inspect.stack()[1][0]).__name__
|
||||
extname = self.extname if hasattr(self, "extname") else self.__guess_extension_name(modname)
|
||||
extname = self.extname if hasattr(self, "extname") \
|
||||
else self.__guess_extension_name(modname)
|
||||
|
||||
@wraps(f)
|
||||
def wrapped_f(*args):
|
||||
if extname:
|
||||
@@ -140,12 +126,12 @@ class observe(object):
|
||||
return []
|
||||
elif not modname in settings.MODOBOA_APPS:
|
||||
return []
|
||||
|
||||
return f(*args)
|
||||
|
||||
map(lambda evt: register(evt, wrapped_f), self.evtnames)
|
||||
for evt in self.evtnames:
|
||||
register(evt, wrapped_f)
|
||||
return wrapped_f
|
||||
|
||||
|
||||
def unregister(event, callback):
|
||||
"""Unregister a callback for a specific event
|
||||
|
||||
@@ -154,7 +140,7 @@ def unregister(event, callback):
|
||||
"""
|
||||
if not event in events:
|
||||
return False
|
||||
if not callbacks.has_key(event):
|
||||
if not event in callbacks:
|
||||
return False
|
||||
fullname = "%s.%s" % (callback.__module__, callback.__name__)
|
||||
try:
|
||||
@@ -162,6 +148,7 @@ def unregister(event, callback):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def raiseEvent(event, *args):
|
||||
"""Raise a specific event
|
||||
|
||||
@@ -172,10 +159,11 @@ def raiseEvent(event, *args):
|
||||
"""
|
||||
if not event in events or not event in callbacks.keys():
|
||||
return 0
|
||||
for name, callback in callbacks[event].iteritems():
|
||||
for callback in callbacks[event].values():
|
||||
callback(*args)
|
||||
return 1
|
||||
|
||||
|
||||
def raiseQueryEvent(event, *args):
|
||||
"""Raise a specific event and wait for answers from callbacks
|
||||
|
||||
@@ -187,10 +175,11 @@ def raiseQueryEvent(event, *args):
|
||||
result = []
|
||||
if not event in events or not event in callbacks.keys():
|
||||
return result
|
||||
for name, callback in callbacks[event].iteritems():
|
||||
for callback in callbacks[event].values():
|
||||
result += callback(*args)
|
||||
return result
|
||||
|
||||
|
||||
def raiseDictEvent(event, *args):
|
||||
"""Raise a specific event and return result as a dictionnary
|
||||
|
||||
@@ -203,7 +192,7 @@ def raiseDictEvent(event, *args):
|
||||
result = {}
|
||||
if not event in events or not event in callbacks.keys():
|
||||
return result
|
||||
for name, callback in callbacks[event].iteritems():
|
||||
for callback in callbacks[event].values():
|
||||
tmp = callback(*args)
|
||||
for k, v in tmp.iteritems():
|
||||
result[k] = v
|
||||
|
||||
+10
-14
@@ -7,18 +7,10 @@ from modoboa.core.models import ObjectAccess
|
||||
import events
|
||||
from exceptions import ModoboaException
|
||||
|
||||
def get_content_type(obj):
|
||||
"""Simple function that use the right method to retrieve a content type
|
||||
|
||||
:param obj: a django model
|
||||
:return: a ``ContentType`` object
|
||||
"""
|
||||
return obj.get_content_type() if hasattr(obj, "get_content_type") \
|
||||
else ContentType.objects.get_for_model(obj)
|
||||
|
||||
def get_account_roles(user):
|
||||
"""Return the list of supported account roles
|
||||
|
||||
|
||||
This list can be extended by extensions which listen to the
|
||||
``GetExtraRoles`` event.
|
||||
|
||||
@@ -32,6 +24,7 @@ def get_account_roles(user):
|
||||
std_roles += events.raiseQueryEvent("GetExtraRoles", user)
|
||||
return sorted(std_roles, key=lambda role: role[1])
|
||||
|
||||
|
||||
def grant_access_to_object(user, obj, is_owner=False):
|
||||
"""Grant access to an object for a given user
|
||||
|
||||
@@ -48,7 +41,7 @@ def grant_access_to_object(user, obj, is_owner=False):
|
||||
:param obj: an admin. object (Domain, Mailbox, ...)
|
||||
:param is_owner: the user is the unique object's owner
|
||||
"""
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
try:
|
||||
entry = user.objectaccess_set.get(content_type=ct, object_id=obj.id)
|
||||
entry.is_owner = is_owner
|
||||
@@ -62,7 +55,7 @@ def grant_access_to_object(user, obj, is_owner=False):
|
||||
ObjectAccess.objects.create(user=user, content_type=ct,
|
||||
object_id=obj.id, is_owner=is_owner)
|
||||
if is_owner:
|
||||
from modoboa.admin.models import User
|
||||
from modoboa.core.models import User
|
||||
for su in User.objects.filter(is_superuser=True):
|
||||
if su == user:
|
||||
continue
|
||||
@@ -74,6 +67,7 @@ def grant_access_to_object(user, obj, is_owner=False):
|
||||
except IntegrityError, e:
|
||||
raise ModoboaException(_("Failed to grant access (%s)" % str(e)))
|
||||
|
||||
|
||||
def grant_access_to_objects(user, objects, ct):
|
||||
"""Grant access to a collection of objects
|
||||
|
||||
@@ -100,7 +94,7 @@ def ungrant_access_to_object(obj, user=None):
|
||||
:param obj: an object inheriting from ``models.Model``
|
||||
:param user: a ``User`` object
|
||||
"""
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
if user:
|
||||
try:
|
||||
ObjectAccess.objects.get(user=user, content_type=ct, object_id=obj.id).delete()
|
||||
@@ -109,22 +103,24 @@ def ungrant_access_to_object(obj, user=None):
|
||||
else:
|
||||
ObjectAccess.objects.filter(content_type=ct, object_id=obj.id).delete()
|
||||
|
||||
|
||||
def ungrant_access_to_objects(objects):
|
||||
"""Cancel all accesses for a given objects list
|
||||
|
||||
:param objects: a list of objects inheriting from ``model.Model``
|
||||
"""
|
||||
for obj in objects:
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
ObjectAccess.objects.filter(content_type=ct, object_id=obj.id).delete()
|
||||
|
||||
|
||||
def get_object_owner(obj):
|
||||
"""Return the unique owner of this object
|
||||
|
||||
:param obj: an object inheriting from ``model.Model``
|
||||
:return: a ``User`` object
|
||||
"""
|
||||
ct = get_content_type(obj)
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
try:
|
||||
entry = ObjectAccess.objects.get(content_type=ct, object_id=obj.id, is_owner=True)
|
||||
except ObjectAccess.DoesNotExist:
|
||||
|
||||
Reference in New Issue
Block a user