From c526a7c90bd6cfab043e1fd5e71b738a511dc28e Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Sat, 2 Nov 2013 15:36:18 +0100 Subject: [PATCH] wip: relay domains. * Documentation update * Few fixes see #491 --- doc/extending/events.rst | 455 ++++++++++++++++-- modoboa/extensions/admin/__init__.py | 1 - modoboa/extensions/admin/models/domain.py | 4 + .../admin/templatetags/admin_tags.py | 12 +- .../postfix_relay_domains/__init__.py | 1 + .../general_callbacks.py | 7 - .../postfix_relay_domains/models.py | 4 + modoboa/lib/events.py | 1 - 8 files changed, 414 insertions(+), 71 deletions(-) diff --git a/doc/extending/events.rst b/doc/extending/events.rst index 083ed7750..69987bd59 100644 --- a/doc/extending/events.rst +++ b/doc/extending/events.rst @@ -11,10 +11,10 @@ Introduction Modoboa provides a simple API to interact with events. It understands two kinds of events: -* Those that return a value -* Those that return nothing +* Those returning a value +* Those returning nothing -Listening to a specific event is achieved as follow:: +Listening to a specific event is achieved as follows:: from modoboa.lib import events @@ -41,12 +41,32 @@ To stop listening to as specific event, you must use the The parameters are the same than those used with ``register``. +To unregister all events declared by a specific extension, use the +``unregister_extension`` function:: + + events.unregister_extension([name]) + +``name`` is the extension's name but it is optional. Leave it empty to +let the function guess the name. + Read further to get a complete list and description of all available events. **************** Supported events **************** +AccountAutoCreated +================== + +Raised when a new account is automatically created (example: LDAP +synchronization). + +*Callback prototype*:: + + def callback(account): pass + +* ``account`` is the newly created account (``User`` instance) + AccountCreated ============== @@ -69,6 +89,32 @@ Raised when an existing account is deleted. * ``account`` is the account that is going to be deleted * ``byuser`` is the adminstrator deleting ``account`` + +AccountExported +=============== + +Raised when an account is exported to CSV. + +*Callback prototype*:: + + def callback(account): pass + +* ``account`` is the account being exported + +Must return a list of values to include in the export. + +AccountImported +=============== + +Raised when an account is imported from CSV. + +*Callback prototype*:: + + def callback(user, account, row): pass + +* ``user`` is the user importing the account +* ``account`` is the account being imported +* ``row`` is a list containing what remains from the CSV definition AccountModified =============== @@ -127,6 +173,21 @@ Raised just before a user tries to create a new object. Return ``True`` or ``False`` to indicate if this user can respectively create or not create a new ``Domain`` object. +CheckDomainName +=============== + +Raised before the unicity of a domain name is checked. By default, +modoboa prevents duplicate names between domains and domain aliases +but extensions have the possibility to extend this rule using this +event. + +*Callback prototype*:: + + def callback(): pass + +Must return a list of 2uple, each one containing a model class and an +associated label. + CheckExtraAccountForm ===================== @@ -144,52 +205,6 @@ this account is concerned by a specific form. Callbacks listening to this event must return a list containing one Boolean. -DomainCreated -============= - -Raised when a new domain is created. - -*Callback prototype*:: - - def callback(user, domain): pass - -* ``user`` corresponds to the ``User`` object creating the domain (its owner) -* ``domain`` is a ``Domain`` instance - -MailboxCreated -============== - -Raised when a new mailbox is created. - -*Callback prototype*:: - - def callback(user, mailbox): pass - -* ``user`` is the new mailbox's owner (``User`` instance) -* ``mailbox`` is the new mailbox (``Mailbox`` instance) - -DomainDeleted -============= - -Raised when an existing domain is about to be deleted. - -*Callback prototype*:: - - def callback(domain): pass - -* ``domain`` is a ``Domain`` instance - -MailboxDeleted -============== - -Raised when an existing mailbox is about to be deleted. - -*Callback prototype*:: - - def callback(mailbox): pass - -* ``mailbox`` is a ``Mailbox`` instance - DomainAliasCreated ================== @@ -213,6 +228,29 @@ Raised when an existing domain alias is about to be deleted. * ``domain_alias`` is a ``DomainAlias`` instance +DomainCreated +============= + +Raised when a new domain is created. + +*Callback prototype*:: + + def callback(user, domain): pass + +* ``user`` corresponds to the ``User`` object creating the domain (its owner) +* ``domain`` is a ``Domain`` instance + +DomainDeleted +============= + +Raised when an existing domain is about to be deleted. + +*Callback prototype*:: + + def callback(domain): pass + +* ``domain`` is a ``Domain`` instance + DomainModified ============== @@ -223,7 +261,20 @@ Raised when a domain has been modified. def callback(domain): pass * ``domain`` is the modified ``Domain`` instance, it contains an extra - ``oldname`` field which contains the old domain name + ``oldname`` field which contains the old name + +DomainOwnershipRemoved +====================== + +Raised before the ownership of a domain is removed from its original +creator. + +*Callback prototype*:: + + def callback(owner, domain): pass + +* ``owner`` is the original creator +* ``domain`` is the ``Domain`` instance being modified ExtDisabled =========== @@ -289,6 +340,37 @@ Let extensions add extra content into the admin panel. Callbacks listening to this event must return a list of string. +ExtraDomainEntries +================== + +Raised to request extra entries to display inside the *domains* +listing. + +*Callback prototype*:: + + def callback(user, domfilter, searchquery, **extrafilters): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user +* ``domfilter`` is a string indicating which domain type the user needs +* ``searchquery`` is a string containing a search query +* ``extrafilters`` is a set of keyword arguments that may contain additional filters + +Must return a valid ``QuerySet``. + +ExtraDomainFilters +================== + +Raised to request extra filters for the *domains* listing page. For +example, the *postfix_relay_domains* extension let users filter +entries based on service types. + +*Callback prototype*:: + + def callback(): pass + +Must return a list of valid filter names (string). + ExtraDomainForm =============== @@ -304,6 +386,59 @@ tabs). * ``domain`` is the domain beeing modified (``Domain`` instance) +Callbacks listening to the event must return a list of dictionnaries, +each one must contain at least three keys:: + + {"id" : "", + "title" : "", + "cls" : TheFormClassName} + +ExtraDomainImportHelp +===================== + +Raised to request extra help text to display inside the domain import +form. + +*Callback prototype*:: + + def callback(): pass + +Must return a list a string. + +ExtraDomainMenuEntries +====================== + +Raised to request extra entries to include in the left menu of the +*domains* listing page. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user + +Must return a list of dictionaries. Each dictionary must contain at +least three keys:: + + {"name": "", + "label": "", + "url": ""} + +ExtraRelayDomainForm +==================== + +Let extensions add new forms to the relay domain edition form (the one +with tabs). + +*Callback prototype*:: + + def callback(user, rdomain): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user +* ``rdomain`` is the relay domain being modified (``RelayDomain`` instance) + Callbacks listening to the event must return a list of dictionnaries, each one must contain at least three keys:: @@ -344,6 +479,24 @@ forms. * ``domain`` is the ``Domain`` instance beeing modified +* ``instances`` is a dictionnary where the callback will add + information needed to fill a specific form + +FillRelayDomainInstances +======================== + +When a relay domain is being modified, this event is raised to fill extra +forms. + +*Callback prototype*:: + + def callback(user, rdomain, instances): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user + +* ``rdomain`` is the ``RelayDomain`` instance being modified + * ``instances`` is a dictionnary where the callback will add information needed to fill a specific form @@ -364,6 +517,73 @@ Some places in the interface let plugins add their own announcement Callbacks listening to this event must return a list of string. +GetDomainActions +================ + +Raised to request the list of actions available for the *domains* +listing entry being displayed. + +*Callback prototype*:: + + def callback(user, rdomain): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user +* ``rdomain`` is the ``RelayDomain`` instance being displayed + +Must return a list of dictionaries, each dictionary containing at +least the following entries:: + + {"name": "", + "url": "", + "title": "", + "img": ""} + +GetDomainModifyLink +=================== + +Raised to request the modification url of the *domains* listing entry +being displayed. + +*Callback prototype*:: + + def callback(domain): pass + +* ``domain`` is a model instance (``RelayDomain`` for example) + +Must return a dictionary containing at least the following entry:: + + {'url': ''} + +GetExtraLimitTemplates +====================== + +Raised to request extra limit templates. For example, the +*postfix_relay_domains* extension define a template to limit the +number of relay domains an administrator can create. + +*Callback prototype*:: + + def callback(): pass + +Must return a list of set. Each set must contain at least three entries:: + + [('', '', '')] + +GetExtraParameters +================== + +Raised to request extra parameters for a given parameters form. + +*Callback prototype*:: + + def callback(application, level): pass + +* ``application`` is the name of the form's application (ie. admin, amavis, etc.) +* ``level`` is the form's level: ``A`` for admin or ``U`` for user + +Must return a dictionary. Each entry must be a valid Django form field. + .. _getextraroles: GetExtraRoles @@ -397,6 +617,27 @@ template but need javascript stuff. Callbacks listening to this event must return a list of string. +ImportObject +============ + +Raised to request the function handling an object being imported from CSV. + +*Callback prototype*:: + + def callback(objtype): pass + +``objtype`` is the type of object being imported + +Must return a list of function. A valid import function must respect +the following prototype:: + + def import_function(user, row, formopts): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user +* ``row`` is a string containing the object's definition (CSV format) +* ``formopts`` is a dictionary that may contain options + MailboxAliasCreated =================== @@ -420,8 +661,31 @@ Raised when an existing mailbox alias is about to be deleted. * ``mailbox_alias`` is an ``Alias`` instance -ModifyMailbox -============= +MailboxCreated +============== + +Raised when a new mailbox is created. + +*Callback prototype*:: + + def callback(user, mailbox): pass + +* ``user`` is the new mailbox's owner (``User`` instance) +* ``mailbox`` is the new mailbox (``Mailbox`` instance) + +MailboxDeleted +============== + +Raised when an existing mailbox is about to be deleted. + +*Callback prototype*:: + + def callback(mailbox): pass + +* ``mailbox`` is a ``Mailbox`` instance + +MailboxModified +=============== Raised when an existing mailbox is modified. @@ -506,3 +770,90 @@ contain at least the following keys:: {"name" : "a_name_without_spaces", "label" : _("The menu label"), "url" : reverse("your_view")} + +RelayDomainAliasCreated +======================= + +Raised when a new relay domain alias is created. + +*Callback prototype*:: + + def callback(user, rdomain_alias): pass + +* ``user`` is the new relay domain alias owner (``User`` instance) +* ``rdomain_alias`` is the new relay domain alias (``DomainAlias`` instance) + +RelayDomainAliasDeleted +======================= + +Raised when an existing relay domain alias is about to be deleted. + +*Callback prototype*:: + + def callback(rdomain_alias): pass + +* ``rdomain_alias`` is a ``RelayDomainAlias`` instance + +RelayDomainCreated +================== + +Raised when a new relay domain is created. + +*Callback prototype*:: + + def callback(user, rdomain): pass + +* ``user`` corresponds to the ``User`` object creating the relay domain (its owner) +* ``rdomain`` is a ``RelayDomain`` instance + +RelayDomainDeleted +================== + +Raised when an existing relay domain is about to be deleted. + +*Callback prototype*:: + + def callback(rdomain): pass + +* ``rdomain`` is a ``RelayDomain`` instance + +RelayDomainModified +=================== + +Raised when a relay domain has been modified. + +*Callback prototype*:: + + def callback(rdomain): pass + +* ``rdomain`` is the modified ``RelayDomain`` instance, it contains an + extra ``oldname`` field which contains the old name + +RoleChanged +=========== + +Raised when the role of an account is about to be changed. + +*Callback prototype*:: + + def callback(account, role): pass + +* ``account`` is the account being modified +* ``role`` is the new role (string) + +UserCanSetRole +============== + +Raised to check if a user is allowed to set a given role to an +account. + +*Callback prototype*:: + + def callback(account, role): pass + +* ``user`` is the ``User`` instance corresponding to the currently + logged in user +* ``role`` is the role ``user`` tries to set + +Must return a list containing ``True`` or ``False`` to indicate if +this user can is allowed to set ``role``. diff --git a/modoboa/extensions/admin/__init__.py b/modoboa/extensions/admin/__init__.py index 0589b630b..8a7629a80 100644 --- a/modoboa/extensions/admin/__init__.py +++ b/modoboa/extensions/admin/__init__.py @@ -19,7 +19,6 @@ admin_events = [ "ExtraDomainFilters", "GetDomainActions", "GetDomainModifyLink", - "GetDomainAliasQuerySet", "CheckDomainName", "DomainAliasCreated", diff --git a/modoboa/extensions/admin/models/domain.py b/modoboa/extensions/admin/models/domain.py index 70166b9b4..95940dda6 100644 --- a/modoboa/extensions/admin/models/domain.py +++ b/modoboa/extensions/admin/models/domain.py @@ -70,6 +70,10 @@ class Domain(AdminObject): """ return [oa.user for oa in self.owners.filter(user__is_superuser=False)] + @property + def aliases(self): + return self.domainalias_set + def add_admin(self, account): """Add a new administrator for this domain diff --git a/modoboa/extensions/admin/templatetags/admin_tags.py b/modoboa/extensions/admin/templatetags/admin_tags.py index 7b9a7c5f7..3f934ddce 100644 --- a/modoboa/extensions/admin/templatetags/admin_tags.py +++ b/modoboa/extensions/admin/templatetags/admin_tags.py @@ -194,18 +194,10 @@ def domain_aliases(domain): :param domain: :rtype: str """ - if domain.__class__.__name__ == "Domain": - qset = domain.domainalias_set - else: - qset = events.raiseQueryEvent('GetDomainAliasQuerySet', domain) - if not qset: - return '---' - qset = qset[0] - - if not qset.count(): + if not domain.aliases.count(): return '---' res = '' - for alias in qset.all(): + for alias in domain.aliases.all(): res += '%s
' % alias.name return res diff --git a/modoboa/extensions/postfix_relay_domains/__init__.py b/modoboa/extensions/postfix_relay_domains/__init__.py index dfe3fff0d..d3451781e 100644 --- a/modoboa/extensions/postfix_relay_domains/__init__.py +++ b/modoboa/extensions/postfix_relay_domains/__init__.py @@ -10,6 +10,7 @@ from .models import RelayDomain, RelayDomainAlias, Service extension_events = [ "RelayDomainCreated", "RelayDomainDeleted", + "RelayDomainModified", "RelayDomainAliasCreated", "RelayDomainAliasDeleted", "ExtraRelayDomainForm", diff --git a/modoboa/extensions/postfix_relay_domains/general_callbacks.py b/modoboa/extensions/postfix_relay_domains/general_callbacks.py index d7fa11bc6..6c9861d36 100644 --- a/modoboa/extensions/postfix_relay_domains/general_callbacks.py +++ b/modoboa/extensions/postfix_relay_domains/general_callbacks.py @@ -71,13 +71,6 @@ def rdomain_modify_link(domain): } -@events.observe('GetDomainAliasQuerySet') -def get_da_query_set(domain): - if domain.__class__.__name__ != 'RelayDomain': - return [] - return [domain.relaydomainalias_set] - - @events.observe('GetDomainActions') def rdomain_actions(user, domain): if not isinstance(domain, RelayDomain): diff --git a/modoboa/extensions/postfix_relay_domains/models.py b/modoboa/extensions/postfix_relay_domains/models.py index 1c45cbffb..360810cb3 100644 --- a/modoboa/extensions/postfix_relay_domains/models.py +++ b/modoboa/extensions/postfix_relay_domains/models.py @@ -105,6 +105,10 @@ class RelayDomain(AdminObject): "type": "srv", "color": "info"} ] + @property + def aliases(self): + return self.relaydomainalias_set + def __str__(self): return self.name diff --git a/modoboa/lib/events.py b/modoboa/lib/events.py index cf565e370..e5baac544 100644 --- a/modoboa/lib/events.py +++ b/modoboa/lib/events.py @@ -125,7 +125,6 @@ def unregister_extension(extension=None): """ if extension is None: extension = guess_extension_name() - print extension for evt, values in callbacks.items(): for name in values.keys(): if extension in name: