diff --git a/demo/__init__.py b/demo/__init__.py
index c6fcc4bad..20ad29592 100755
--- a/demo/__init__.py
+++ b/demo/__init__.py
@@ -35,6 +35,10 @@ def announcement(**kwargs):
return [txt]
return ""
+def password_change(user):
+ return [user.id == 1]
+
if 'modoboa.demo' in settings.INSTALLED_APPS:
events.register("UserMenuDisplay", menu)
events.register("GetAnnouncement", announcement)
+ events.register("PasswordChange", password_change)
diff --git a/doc/plugin_api.rst b/doc/plugin_api.rst
index ba48a4036..13c1e61ea 100644
--- a/doc/plugin_api.rst
+++ b/doc/plugin_api.rst
@@ -256,6 +256,17 @@ callbacks and indicates the place where the announcement will appear:
Callbacks listening to this event must return a list of string.
+PasswordChange
+--------------
+
+Raised just before a *password change* action. The associated ``User``
+object is provided inside the ``user`` keyword argument.
+
+Callbacks listening to this event must return a list containing either
+``True`` or ``False``. If at least one ``True`` is returned, the
+*password change* will be cancelled (ie. changing the password for
+this user is disabled).
+
Parameters
==========
diff --git a/lib/events.py b/lib/events.py
index 631486e26..434dd358a 100644
--- a/lib/events.py
+++ b/lib/events.py
@@ -12,6 +12,8 @@ events = ["CreateDomain",
"DeleteMailbox",
"ModifyMailbox",
+ "PasswordChange",
+
"UserMenuDisplay",
"AdminMenuDisplay",
diff --git a/templates/common/error_simple.html b/templates/common/error_simple.html
new file mode 100644
index 000000000..ddebe672e
--- /dev/null
+++ b/templates/common/error_simple.html
@@ -0,0 +1,4 @@
+{% extends "layout_simple.html" %}
+{% block content %}
+
+{% endblock %}
diff --git a/userprefs/views.py b/userprefs/views.py
index cab96d0c5..cfe3a55cc 100644
--- a/userprefs/views.py
+++ b/userprefs/views.py
@@ -3,9 +3,10 @@ from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators \
import login_required, user_passes_test
+from django.conf import settings
from django.utils.translation import ugettext as _
-from modoboa.lib import parameters
-from modoboa.lib.webutils import _render, ajax_response
+from modoboa.lib import parameters, events
+from modoboa.lib.webutils import _render, _render_error, ajax_response
from forms import *
from modoboa.admin.models import Mailbox, Alias
from modoboa.admin.lib import is_domain_admin
@@ -21,6 +22,11 @@ def changepassword(request, tplname="userprefs/chpassword.html"):
target = request.user
else:
target = Mailbox.objects.get(user=request.user.id)
+ res = events.raiseQueryEvent("PasswordChange", user=request.user)
+ if True in res:
+ ctx = dict(error=_("Password change is disabled for this user"))
+ return _render_error(request, errortpl="error_simple", user_context=ctx)
+
error = None
if request.method == "POST":
form = ChangePasswordForm(target, request.POST)
@@ -32,7 +38,8 @@ def changepassword(request, tplname="userprefs/chpassword.html"):
request.session["password"] = encrypt(request.POST["confirmation"])
target.save()
return ajax_response(request, respmsg=_("Password changed"))
- return ajax_response(request, status="ko", template=tplname, form=form, error=error)
+ return ajax_response(request, status="ko", template=tplname,
+ form=form, error=error)
form = ChangePasswordForm(target)
return _render(request, 'userprefs/chpassword.html', {