Files
modoboa/lib/events.py
T

171 lines
4.4 KiB
Python

# -*- coding: utf-8 -*-
"""
:mod:`events` --- simple events handling
----------------------------------------
This module provides a simple way of managing events between Modoboa
core application and additional components.
"""
from functools import wraps
import inspect
import re
from django.conf import settings
events = [
"CanCreate",
"CreateDomain",
"DeleteDomain",
"DomainAliasCreated",
"DomainAliasDeleted",
"CreateMailbox",
"DeleteMailbox",
"ModifyMailbox",
"MailboxAliasCreated",
"MailboxAliasDeleted",
"AccountCreated",
"AccountModified",
"AccountDeleted",
"PasswordChange",
"UserMenuDisplay",
"AdminMenuDisplay",
"GetStaticContent",
"ExtraAccountForm",
"CheckExtraAccountForm",
"FillAccountInstances",
"GetExtraRoles",
"ExtEnabled",
"ExtDisabled",
"UserLogin",
"UserLogout",
"GetAnnouncement",
"TopNotifications",
"ExtraAdminContent",
]
callbacks = {}
def register(event, callback):
"""Register a plugin callback for a specific event
The event must be declared in this module.
:param event: the event to listen to
:param callback: a function to execute when the event is raised
"""
if not event in events:
return 0
if not event in callbacks.keys():
callbacks[event] = {}
fullname = "%s.%s" % (callback.__module__, callback.__name__)
if not callbacks[event].has_key(fullname):
callbacks[event][fullname] = callback
return 1
class observe(object):
"""Event observing decorator
Automatically register the decorated function to observe the given
event. If the decorated function is located into an extension, we
check before each call if the extension is enabled or not. If
that's not the case, the callback is not called.
.. note::
That's not a really optimized behaviour but I haven't found
another solution to achieve that feature.
:param evtname: the event's name
"""
def __init__(self, *evtnames, **kwargs):
self.evtnames = evtnames
if kwargs.has_key("extname"):
self.extname = kwargs["extname"]
def __guess_extension_name(self, modname):
if modname.startswith('modoboa.extensions'):
m = re.match(r'modoboa\.extensions\.([^\.]+)', modname)
if m:
return m.group(1)
return None
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)
@wraps(f)
def wrapped_f(*args):
if extname:
from modoboa.admin.models import Extension
try:
ext = Extension.objects.get(name=extname)
except Extension.DoesNotExist:
return []
if not ext.enabled:
return []
elif not modname in settings.INSTALLED_APPS:
return []
return f(*args)
map(lambda evt: register(evt, wrapped_f), self.evtnames)
return wrapped_f
def unregister(event, callback):
"""Unregister a callback for a specific event
:param event: the targeted event
:param callback: the callback to remove
"""
if not event in events:
return False
if not callbacks.has_key(event):
return False
fullname = "%s.%s" % (callback.__module__, callback.__name__)
try:
del callbacks[event][fullname]
except KeyError:
pass
def raiseEvent(event, *args):
"""Raise a specific event
Any additional keyword argument will be passed to registered
callbacks.
:param event: the event to raise
"""
if not event in events or not event in callbacks.keys():
return 0
for name, callback in callbacks[event].iteritems():
callback(*args)
return 1
def raiseQueryEvent(event, *args):
"""Raise a specific event and wait for answers from callbacks
Any additional keyword argument will be passed to registered
callbacks. Callback answers are returned as a list.
:param event: the event to raise
"""
result = []
if not event in events or not event in callbacks.keys():
return result
for name, callback in callbacks[event].iteritems():
result += callback(*args)
return result