hooks.py 2.91 KB
Newer Older
1
"""this module contains server side hooks for cleaning forgotpwd table
Charles Hebert's avatar
0.1.0  
Charles Hebert committed
2
3
"""

4
5
6
7
8
9
import random
import string
from datetime import datetime, timedelta

from logilab.common.decorators import monkeypatch
from yams import ValidationError
Sylvain Thénault's avatar
Sylvain Thénault committed
10

11
from cubicweb.selectors import is_instance
12
from cubicweb.crypto import encrypt
Sylvain Thénault's avatar
Sylvain Thénault committed
13
from cubicweb.server import hook
14
from cubicweb.server.repository import Repository
15
16
17
from cubicweb.sobjects.notification import NotificationView

_ = unicode
Charles Hebert's avatar
0.1.0  
Charles Hebert committed
18

Sylvain Thénault's avatar
Sylvain Thénault committed
19
20
21
class ServerStartupHook(hook.Hook):
    """on startup, register a task to delete old revocation key"""
    __regid__ = 'fpwd_startup'
Charles Hebert's avatar
0.1.0  
Charles Hebert committed
22
    events = ('server_startup',)
Sylvain Thénault's avatar
Sylvain Thénault committed
23
24
25
26
27

    def __call__(self):
        # XXX use named args and inner functions to avoid referencing globals
        # which may cause reloading pb
        def cleaning_revocation_key(repo, now=datetime.now):
28
29
30
31
            with repo.internal_cnx() as cnx:
                cnx.execute('DELETE Fpasswd F WHERE F revocation_date < %(date)s',
                            {'date': now()})
                cnx.commit()
32
        # run looping task often enough to purge pwd-reset requests
Sylvain Thénault's avatar
Sylvain Thénault committed
33
34
        limit = self.repo.vreg.config['revocation-limit'] * 60
        self.repo.looping_task(limit, cleaning_revocation_key, self.repo)
35
36
37


class PasswordResetNotification(NotificationView):
Sylvain Thénault's avatar
Sylvain Thénault committed
38
    __regid__ = 'notif_after_add_entity'
39
    __select__ = is_instance('Fpasswd')
40

41
42
    content = _('''There was recently a request to change the password of your account
on %(base_url)s (login: %(login)s).
43
44
45
46
47
48
49
50
51
52
53
54
If you requested this password change, please set a new password by following
the link below:

%(resetlink)s

If you do not want to change your password, you may ignore this message. The
link expires in %(limit)s minutes.

See you soon on %(base_url)s !
''')

    def subject(self):
55
        return self._cw._(u'[%s] Request to change your password' % self._cw.base_url())
56
57

    def recipients(self):
58
        fpasswd = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
59
        user = fpasswd.reverse_has_fpasswd[0]
60
        return [(user.cw_adapt_to('IEmailable').get_email(), user.property_value('ui.language'))]
61
62

    def context(self, **kwargs):
63
64
        fpasswd = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
        user = fpasswd.reverse_has_fpasswd[0]
65
66
67
68
69
70
71
        data = {}
        data['use_email'] = user.cw_adapt_to('IEmailable').get_email()
        data['revocation_id'] = fpasswd.revocation_id
        key = encrypt(data, self._cw.vreg.config['forgotpwd-cypher-seed'])
        url = self._cw.build_url('forgottenpasswordrequest',
                                 __secure__=True,
                                 key=key,)
72
        return {
73
            'resetlink': url,
74
            'login': user.login,
75
76
            # NOTE: it would probably be better to display the expiration date
            #       (with correct timezone)
Sylvain Thénault's avatar
Sylvain Thénault committed
77
78
            'limit': self._cw.vreg.config['revocation-limit'],
            'base_url': self._cw.base_url(),
79
            }
80