diff --git a/admin/models.py b/admin/models.py index e75ae0898..9055bd63a 100644 --- a/admin/models.py +++ b/admin/models.py @@ -295,15 +295,14 @@ class DatesAware(models.Model): ObjectDates.set_for_object(self) super(DatesAware, self).save(*args, **kwargs) - def __creation(self): + @property + def creation(self): return self.dates.creation - def __last_modification(self): + @property + def last_modification(self): return self.dates.last_modification - creation = property(__creation) - last_modification = property(__last_modification) - class Domain(DatesAware): name = models.CharField(ugettext_noop('name'), max_length=100, unique=True, help_text=ugettext_noop("The domain name")) @@ -317,14 +316,14 @@ class Domain(DatesAware): ("view_domain", "View domain"), ("view_domains", "View domains"), ) - - def __domainalias_count(self): + + @property + def domainalias_count(self): return len(self.domainalias_set.all()) - domainalias_count = property(__domainalias_count) - def __mailbox_count(self): + @property + def mailbox_count(self): return len(self.mailbox_set.all()) - mailbox_count = property(__mailbox_count) def create_dir(self): if parameters.get_admin("CREATE_DIRECTORIES") == "yes": @@ -407,25 +406,25 @@ class Mailbox(DatesAware): self.mdirroot += '/' def __str__(self): - return self.__full_address() - - def __full_address(self): + return self.full_address + + @property + def full_address(self): return "%s@%s" % (self.address, self.domain.name) - full_address = property(__full_address) - def __enabled(self): + @property + def enabled(self): return self.user.is_active - enabled = property(__enabled) - def __full_path(self): + @property + def full_path(self): path = os.path.join(parameters.get_admin("STORAGE_PATH"), self.domain.name, self.address) return os.path.abspath(path) - full_path = property(__full_path) - def __alias_count(self): + @property + def alias_count(self): return len(self.alias_set.all()) - alias_count = property(__alias_count) def create_dir(self): if parameters.get_admin("CREATE_DIRECTORIES") == "yes": @@ -607,15 +606,15 @@ class Alias(DatesAware): ("view_aliases", "View aliases"), ) - def __full_address(self): + @property + def full_address(self): return "%s@%s" % (self.address, self.domain.name) - full_address = property(__full_address) - def __targets(self): + @property + def targets(self): ret = "".join(map(lambda m: str(m), self.mboxes.all())) ret += "" + self.repr_extmboxes() return ret - targets = property(__targets) def save(self, int_targets, ext_targets, *args, **kwargs): if len(ext_targets): diff --git a/admin/tables.py b/admin/tables.py index bcd15cd2a..5fd152771 100644 --- a/admin/tables.py +++ b/admin/tables.py @@ -21,7 +21,7 @@ class DomainsTable(tables.Table): width="50px", align="center") enabled = tables.Column("enabled", label=gender("Enabled", "m"), width="50px", align="center") - actions = tables.ActionColumn("actions", label=ugettext_noop("Actions"), width="50px", + actions = tables.ActionColumn("actions", label=ugettext_noop("Actions"), width="70px", align="center", defvalue=domain_actions) cols_order = ["name", "creation", "modified", @@ -67,7 +67,7 @@ class MailboxesTable(tables.Table): tableid = "objects_table" idkey = "id" - address = tables.Column("address", label=ugettext_noop("Address")) + address = tables.Column("full_address", label=ugettext_noop("Address")) name = tables.Column("user", label=ugettext_noop("Name")) creation = tables.Column("creation", label=ugettext_noop("Created"), width="160px") diff --git a/admin/templatetags/admin_extras.py b/admin/templatetags/admin_extras.py index 90f819ea4..76f0ba1c8 100644 --- a/admin/templatetags/admin_extras.py +++ b/admin/templatetags/admin_extras.py @@ -169,6 +169,15 @@ def domain_actions(user, domid): "img" : static_url("pics/alias.png"), "title" : _("View aliases of this domain")} ] + if user.has_perm('admin.view_domains'): + actions += [ + {"name" : "viewadmins", + "url" : reverse(admin.views.view_domain_admins, args=[domid]), + "img" : static_url("pics/administrators.png"), + "title" : _("View administrators of this domain"), + "class" : "boxed", + "rel" : "{handler:'iframe',size:{x:310,y:190}}"}, + ] return render_actions(actions) @register.simple_tag diff --git a/admin/urls.py b/admin/urls.py index fe48c7bd7..a47f8a591 100644 --- a/admin/urls.py +++ b/admin/urls.py @@ -37,6 +37,7 @@ urlpatterns = patterns( (r'^permissions/domainadmin/edit/(?P\d+)/$', 'edit_domain_admin'), (r'^permissions/domainadmin/promote/$', 'domain_admin_promotion'), (r'^permissions/domainadmin/assign/(?P\d+)/$', 'assign_domains_to_admin'), + (r'^permissions/domainadmins/(?P\d+)/$', 'view_domain_admins'), (r'^permissions/searchaccount/$', 'search_account'), (r'^permissions/delete/$', 'delete_permissions'), ) diff --git a/admin/views.py b/admin/views.py index 0580e7fb9..e70b52516 100644 --- a/admin/views.py +++ b/admin/views.py @@ -70,7 +70,7 @@ def _validate_domain(request, form, successmsg, commonctx, @permission_required("admin.add_domain") @transaction.commit_on_success def newdomain(request, tplname="admin/adminform.html"): - events.raiseEvent("CanCreateDomain", request.user) + events.raiseEvent("CanCreate", request.user, "domains") def newdomain_cb(user, domain): grant_access_to_object(user, domain, is_owner=True) events.raiseEvent("CreateDomain", user, domain) @@ -152,7 +152,7 @@ def domaliases(request): @permission_required("admin.add_domainalias") @transaction.commit_on_success def newdomalias(request, tplname="admin/adminform.html"): - events.raiseEvent("CanCreateDomainAlias", request.user) + events.raiseEvent("CanCreate", request.user, "domain_aliases") commonctx = {"title" : _("New domain alias"), "submit_label" : _("Create"), "action" : reverse(newdomalias), @@ -275,7 +275,7 @@ def mailboxes_search(request): @permission_required("admin.add_mailbox") @transaction.commit_on_success def newmailbox(request, tplname="admin/adminform.html"): - events.raiseEvent("CanCreateMailbox", request.user) + events.raiseEvent("CanCreate", request.user, "mailboxes") commonctx = {"title" : _("New mailbox"), "submit_label" : _("Create"), "action" : reverse(newmailbox), @@ -312,7 +312,7 @@ def newmailbox(request, tplname="admin/adminform.html"): @permission_required("admin.change_mailbox") def editmailbox(request, mbox_id=None, tplname="admin/adminform.html"): mb = Mailbox.objects.get(pk=mbox_id) - if not request.user.is_owner(mb.domain): + if not request.user.can_access(mb.domain): raise PermDeniedException(_("You do not have access to this domain")) commonctx = {"title" : _("Mailbox editing"), @@ -423,7 +423,7 @@ def _validate_mbalias(request, form, successmsg, tplname, commonctx, callback=No @permission_required("admin.add_alias") @transaction.commit_on_success def newmbalias(request, tplname="admin/mbaliasform.html"): - events.raiseEvent("CanCreateMailboxAlias", request.user) + events.raiseEvent("CanCreate", request.user, "mailbox_aliases") commonctx = {"title" : _("New mailbox alias"), "submit_label" : _("Create"), "action" : reverse(newmbalias), @@ -496,7 +496,7 @@ def permissions(request, tplname='admin/permissions.html'): permtables += [ {"id" : "domain_admins", "title" : _("Domain administrators"), - "rel" : "350 250", + "rel" : "350 100", "content" : DomainAdminsPerms().get(request)} ] @@ -515,6 +515,7 @@ def add_permission(request): else: pobj = pclass() if request.method == "GET": + events.raiseEvent("CanCreate", request.user, role) return pobj.get_add_form(request) status, data = pobj.add(request) if not status: @@ -573,7 +574,7 @@ def edit_domain_admin(request, da_id, tplname="admin/adminform.html"): @login_required @permission_required("auth.view_permissions") -def domain_admin_promotion(request): +def domain_admin_promotion(request, tplname="admin/domain_admin_promotion.html"): if request.method == "POST": form = DomainAdminPromotionForm(request.POST) if form.is_valid(): @@ -589,9 +590,10 @@ def domain_admin_promotion(request): messages.info(request, _("Domain admin added"), fail_silently=True) return ajax_response(request, url=reverse(admin.views.permissions)) + return ajax_response(request, status="ko", template=tplname, form=form) + form = DomainAdminPromotionForm() - return ajax_response(request, template="admin/domain_admin_promotion.html", - form=form) + return ajax_response(request, template=tplname, form=form) @login_required @permission_required("auth.view_permissions") @@ -624,6 +626,14 @@ def assign_domains_to_admin(request, da_id, tplname="admin/adminform.html"): ctx.update(form=form) return _render(request, tplname, ctx) +@login_required +@permission_required("auth.view_permissions") +def view_domain_admins(request, dom_id, tplname="admin/view_domain_admins.html"): + domain = Domain.objects.get(pk=dom_id) + return _render(request, tplname, { + "domain" : domain + }) + @login_required @permission_required("auth.view_permissions") @check_domain_access diff --git a/extensions/limits/controls.py b/extensions/limits/controls.py index 130050f58..12ef82b78 100644 --- a/extensions/limits/controls.py +++ b/extensions/limits/controls.py @@ -40,9 +40,6 @@ def dec_limit(user, lname): except LimitsPool.DoesNotExist: pass -@events.observe('CanCreateDomain') -def check_domains_limit(user): - check_limit(user, 'domains_limit') @events.observe('CreateDomain') def inc_nb_domains(user, domain): @@ -59,10 +56,6 @@ def dec_nb_domains(domain): for mbalias in domain.alias_set.all(): dec_nb_mbaliases(mbalias) -@events.observe('CanCreateDomainAlias') -def check_domaliases_limit(user): - check_limit(user, 'domain_aliases_limit') - @events.observe('DomainAliasCreated') def inc_nb_domaliases(user, domalias): inc_limit(user, 'domain_aliases_limit') @@ -72,10 +65,6 @@ def dec_nb_domaliases(domainalias): owner = get_object_owner(domainalias) dec_limit(owner, 'domain_aliases_limit') -@events.observe('CanCreateMailbox') -def check_mboxes_limit(user): - check_limit(user, 'mailboxes_limit') - @events.observe('CreateMailbox') def inc_nb_mailboxes(user, mailbox): inc_limit(user, 'mailboxes_limit') @@ -85,10 +74,6 @@ def dec_nb_mailboxes(mailbox): owner = get_object_owner(mailbox) dec_limit(owner, 'mailboxes_limit') -@events.observe('CanCreateMailboxAlias') -def check_mbaliases_limit(user): - check_limit(user, 'mailbox_aliases_limit') - @events.observe('MailboxAliasCreated') def inc_nb_mbaliases(user, mailboxalias): inc_limit(user, 'mailbox_aliases_limit') @@ -98,8 +83,14 @@ def dec_nb_mbaliases(mailboxalias): owner = get_object_owner(mailboxalias) dec_limit(owner, 'mailbox_aliases_limit') +@events.observe('CanCreate') +def can_create_new_object(user, objtype): + check_limit(user, '%s_limit' % objtype) + @events.observe("DomainAdminCreated") def create_pool(user): + owner = get_object_owner(user) + inc_limit(owner, 'domain_admins_limit') p = LimitsPool(user=user) p.save() p.create_limits() @@ -108,6 +99,8 @@ def create_pool(user): def move_pool_resource(user): owner = get_object_owner(user) if not owner.is_superuser: + dec_limit(owner, 'domain_admins_limit') + for ooentry in user.objectaccess_set.all(): if ooentry.is_owner: grant_access_to_object(owner, ooentry.content_object, True) diff --git a/extensions/limits/forms.py b/extensions/limits/forms.py index 77d0e742e..50554d91c 100644 --- a/extensions/limits/forms.py +++ b/extensions/limits/forms.py @@ -30,6 +30,10 @@ class ResellerWithPasswordForm(ResellerForm, UserWithPasswordForm): pass class ResellerPoolForm(forms.Form): + domain_admins_limit = forms.IntegerField( + ugettext_noop("Max domain admins"), + help_text=ugettext_noop("Maximum number of domain administrators that can be created by this user") + ) domains_limit = forms.IntegerField(ugettext_noop("Max domains"), help_text=ugettext_noop("Maximum number of domains that can be created by this user")) domain_aliases_limit = forms.IntegerField(ugettext_noop("Max domain aliases"), diff --git a/extensions/limits/models.py b/extensions/limits/models.py index 9c26ac570..90694e592 100644 --- a/extensions/limits/models.py +++ b/extensions/limits/models.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext as _, ugettext_noop from modoboa.admin.models import User reseller_limits_tpl = [ + "domain_admins_limit", "domains_limit", "domain_aliases_limit", "mailboxes_limit", diff --git a/extensions/limits/templatetags/limits_tags.py b/extensions/limits/templatetags/limits_tags.py index e61597397..37310b0d2 100644 --- a/extensions/limits/templatetags/limits_tags.py +++ b/extensions/limits/templatetags/limits_tags.py @@ -39,6 +39,6 @@ def reseller_actions(user, resid): "img" : static_url("pics/settings.png"), "title" : _("Edit limits allocated to this reseller"), "class" : "boxed", - "rel" : "{handler:'iframe',size:{x:330,y:280}}"}, + "rel" : "{handler:'iframe',size:{x:330,y:310}}"}, ] return render_actions(actions) diff --git a/extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html b/extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html index 7f8790c35..c7a9a6fe2 100644 --- a/extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html +++ b/extensions/postfix_autoreply/templates/postfix_autoreply/autoreply.html @@ -16,8 +16,9 @@ @@ -29,7 +31,8 @@ $(document).addEvent("domready", function() { {% block content %} {{ title }} {% if error %}{{ error }}{% endif %} - + {% include "common/genericform.html" %} diff --git a/extensions/sievefilters/views.py b/extensions/sievefilters/views.py index 59774e488..70c2dba2a 100644 --- a/extensions/sievefilters/views.py +++ b/extensions/sievefilters/views.py @@ -28,9 +28,9 @@ def index(request, tplname="sievefilters/index.html"): return _render_error(request, user_context={"error" : e}) if active_script is None: active_script = "" - default_script = scripts[0] if len(scripts) else "" + default_script = "%s/" % scripts[0] if len(scripts) else "" else: - default_script = active_script + default_script = "%s/" % active_script return _render(request, tplname, { "active_script" : active_script, "default_script" : default_script, diff --git a/extensions/stats/grapher.py b/extensions/stats/grapher.py index ad52da760..4237ed7d9 100644 --- a/extensions/stats/grapher.py +++ b/extensions/stats/grapher.py @@ -3,7 +3,6 @@ import os import time import datetime -import rrdtool from django.utils.translation import ugettext as _ from modoboa.lib import parameters @@ -77,6 +76,8 @@ class Grapher(object): self.img_rootdir = parameters.get_admin("IMG_ROOTDIR") def process(self, target, suffix, start, end, tpl=traffic_avg_template): + import rrdtool + rrdfile = "%s/%s.rrd" % (self.rrd_rootdir, target) if not os.path.exists(rrdfile): return diff --git a/extensions/webmail/__init__.py b/extensions/webmail/__init__.py index 59fe71733..c044e3824 100644 --- a/extensions/webmail/__init__.py +++ b/extensions/webmail/__init__.py @@ -5,6 +5,8 @@ from modoboa.lib import events, parameters from modoboa.lib.webutils import static_url def load(): + parameters.register_app(uparams_opts=dict(needs_mailbox=True)) + parameters.register_admin("IMAP_SERVER", type="string", deflt="127.0.0.1", help=_("Address of your IMAP server")) @@ -30,7 +32,6 @@ def load(): parameters.register_admin("MAX_ATTACHMENT_SIZE", type="int", deflt=2048, help=_("Maximum attachment size in bytes (or KB, MB, GB if specified)")) - parameters.register_user("MESSAGES_PER_PAGE", type="int", deflt=40, label=_("Number of displayed emails per page"), help=_("Sets the maximum number of messages displayed in a page")) diff --git a/extensions/webmail/templates/webmail/folder.html b/extensions/webmail/templates/webmail/folder.html index 1abc6a5b2..62af3b982 100644 --- a/extensions/webmail/templates/webmail/folder.html +++ b/extensions/webmail/templates/webmail/folder.html @@ -6,6 +6,8 @@ + {% endblock %} {% block content %} {% load i18n %} diff --git a/tools/pfxadmin_migrate/migrate.py b/tools/pfxadmin_migrate/migrate.py index 0bce33811..499818a52 100755 --- a/tools/pfxadmin_migrate/migrate.py +++ b/tools/pfxadmin_migrate/migrate.py @@ -115,9 +115,7 @@ def migrate_mailboxes(domain, options): old_mboxes = pf_models.Mailbox.objects.using(options._from).filter(domain=domain.name) for old_mb in old_mboxes: new_mb = md_models.Mailbox() - new_mb.name = old_mb.name new_mb.address = old_mb.local_part - new_mb.password = old_mb.password new_mb.domain = domain new_mb.dates = migrate_dates(old_mb) if old_mb.quota: @@ -132,7 +130,7 @@ def migrate_mailboxes(domain, options): print "Error: cannot rename mailbox directory\n%s" % output sys.exit(1) - new_mb.save(using=options.to) + new_mb.save(name=old_mb.name, password=old_mb.password, using=options.to) def migrate_domain(old_dom, options): @@ -161,29 +159,27 @@ def migrate_admins(options): print "Warning: skipping useless admin %s" % (old_admin.username) continue try: - mb = md_models.Mailbox.objects.using(options.to).get(user__username=old_admin.username) - except md_models.Mailbox.DoesNotExist: + user = md_models.User.objects.using(options.to).get(username=old_admin.username) + except md_models.User.DoesNotExist: try: domain = md_models.Domain.objects.using(options.to).get(name=domname) except md_models.Domain.DoesNotExist: print "Warning: skipping domain admin %s, domain not found" \ % old_admin.username continue - mb = md_models.Mailbox() - mb.address = local_part - mb.domain = domain - mb.name = local_part - mb.enabled = old_admin.active - mb.password = old_admin.password - mb.dates = migrate_dates(old_admin) - mb.save(using=options.to) + user = md_models.User() + user.username = old_admin.username + user.email = old_admin.username + user.password = old_admin.password + user.is_active = old_admin.active + user.save(using=options.to) - mb.user.date_joined = old_admin.modified + user.date_joined = old_admin.modified if creds.domain == "ALL": - mb.user.is_superuser = True + user.is_superuser = True else: - mb.user.groups.add(dagroup) - mb.save(using=options.to) + user.groups.add(dagroup) + user.save(using=options.to) def do_migration(options): pf_domains = pf_models.Domain.objects.using(options._from).all() diff --git a/userprefs/views.py b/userprefs/views.py index 0f996a8d6..287995afc 100644 --- a/userprefs/views.py +++ b/userprefs/views.py @@ -95,6 +95,10 @@ def preferences(request): for app in apps: if not len(parameters._params[app]['U']): continue + if parameters.get_app_option('U', 'needs_mailbox', False, app=app) \ + and not request.user.has_mailbox: + continue + tmp = {"name" : app, "params" : []} for p in parameters._params_order[app]['U']: param_def = parameters._params[app]['U'][p]