Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / models.py @ e9083112

History | View | Annotate | Download (14.5 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 6c736ed7 Kostas Papadimitriou
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 6c736ed7 Kostas Papadimitriou
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 6c736ed7 Kostas Papadimitriou
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 6c736ed7 Kostas Papadimitriou
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 6c736ed7 Kostas Papadimitriou
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 64cd4730 Antony Chazapis
34 64cd4730 Antony Chazapis
import hashlib
35 15efc749 Sofia Papagiannaki
import uuid
36 18ffbee1 Sofia Papagiannaki
import logging
37 0a569195 Sofia Papagiannaki
import json
38 64cd4730 Antony Chazapis
39 64cd4730 Antony Chazapis
from time import asctime
40 64cd4730 Antony Chazapis
from datetime import datetime, timedelta
41 64cd4730 Antony Chazapis
from base64 import b64encode
42 0a569195 Sofia Papagiannaki
from urlparse import urlparse, urlunparse
43 8f5a3a06 Sofia Papagiannaki
from random import randint
44 64cd4730 Antony Chazapis
45 49790d9d Sofia Papagiannaki
from django.db import models, IntegrityError
46 18ffbee1 Sofia Papagiannaki
from django.contrib.auth.models import User, UserManager, Group
47 0a569195 Sofia Papagiannaki
from django.utils.translation import ugettext as _
48 0a569195 Sofia Papagiannaki
from django.core.exceptions import ValidationError
49 49790d9d Sofia Papagiannaki
from django.template.loader import render_to_string
50 49790d9d Sofia Papagiannaki
from django.core.mail import send_mail
51 49790d9d Sofia Papagiannaki
from django.db import transaction
52 ff9290ec Sofia Papagiannaki
from django.db.models.signals import post_save, post_syncdb
53 64cd4730 Antony Chazapis
54 49790d9d Sofia Papagiannaki
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, \
55 111f3da6 Sofia Papagiannaki
    AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_CONNECTION, SITENAME, \
56 111f3da6 Sofia Papagiannaki
    EMAILCHANGE_ACTIVATION_DAYS, LOGGING_LEVEL
57 9c01d9d1 Sofia Papagiannaki
58 9c01d9d1 Sofia Papagiannaki
QUEUE_CLIENT_ID = 3 # Astakos.
59 64cd4730 Antony Chazapis
60 18ffbee1 Sofia Papagiannaki
logger = logging.getLogger(__name__)
61 18ffbee1 Sofia Papagiannaki
62 0905ccd2 Sofia Papagiannaki
class AstakosUser(User):
63 890b0eaf Sofia Papagiannaki
    """
64 890b0eaf Sofia Papagiannaki
    Extends ``django.contrib.auth.models.User`` by defining additional fields.
65 890b0eaf Sofia Papagiannaki
    """
66 0905ccd2 Sofia Papagiannaki
    # Use UserManager to get the create_user method, etc.
67 0905ccd2 Sofia Papagiannaki
    objects = UserManager()
68 6c736ed7 Kostas Papadimitriou
69 5ed6816e Sofia Papagiannaki
    affiliation = models.CharField('Affiliation', max_length=255, blank=True)
70 5ed6816e Sofia Papagiannaki
    provider = models.CharField('Provider', max_length=255, blank=True)
71 6c736ed7 Kostas Papadimitriou
72 64cd4730 Antony Chazapis
    #for invitations
73 92defad4 Sofia Papagiannaki
    user_level = DEFAULT_USER_LEVEL
74 a196eb7e Sofia Papagiannaki
    level = models.IntegerField('Inviter level', default=user_level)
75 ebd369d0 Sofia Papagiannaki
    invitations = models.IntegerField('Invitations left', default=INVITATIONS_PER_LEVEL.get(user_level, 0))
76 6c736ed7 Kostas Papadimitriou
77 64cd4730 Antony Chazapis
    auth_token = models.CharField('Authentication Token', max_length=32,
78 0905ccd2 Sofia Papagiannaki
                                  null=True, blank=True)
79 0905ccd2 Sofia Papagiannaki
    auth_token_created = models.DateTimeField('Token creation date', null=True)
80 0905ccd2 Sofia Papagiannaki
    auth_token_expires = models.DateTimeField('Token expiration date', null=True)
81 6c736ed7 Kostas Papadimitriou
82 64cd4730 Antony Chazapis
    updated = models.DateTimeField('Update date')
83 890b0eaf Sofia Papagiannaki
    is_verified = models.BooleanField('Is verified?', default=False)
84 6c736ed7 Kostas Papadimitriou
85 15efc749 Sofia Papagiannaki
    # ex. screen_name for twitter, eppn for shibboleth
86 15efc749 Sofia Papagiannaki
    third_party_identifier = models.CharField('Third-party identifier', max_length=255, null=True, blank=True)
87 6c736ed7 Kostas Papadimitriou
88 ebd369d0 Sofia Papagiannaki
    email_verified = models.BooleanField('Email verified?', default=False)
89 6c736ed7 Kostas Papadimitriou
90 59f598f1 Sofia Papagiannaki
    has_credits = models.BooleanField('Has credits?', default=False)
91 270dd48d Sofia Papagiannaki
    has_signed_terms = models.BooleanField('Agree with the terms?', default=False)
92 0a569195 Sofia Papagiannaki
    date_signed_terms = models.DateTimeField('Signed terms date', null=True, blank=True)
93 59f598f1 Sofia Papagiannaki
    
94 751d24cf Sofia Papagiannaki
    activation_sent = models.DateTimeField('Activation sent data', null=True, blank=True)
95 751d24cf Sofia Papagiannaki
    
96 18ffbee1 Sofia Papagiannaki
    __has_signed_terms = False
97 18ffbee1 Sofia Papagiannaki
    __groupnames = []
98 18ffbee1 Sofia Papagiannaki
    
99 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
100 18ffbee1 Sofia Papagiannaki
        super(AstakosUser, self).__init__(*args, **kwargs)
101 18ffbee1 Sofia Papagiannaki
        self.__has_signed_terms = self.has_signed_terms
102 18ffbee1 Sofia Papagiannaki
        if self.id:
103 18ffbee1 Sofia Papagiannaki
            self.__groupnames = [g.name for g in self.groups.all()]
104 18ffbee1 Sofia Papagiannaki
        else:
105 18ffbee1 Sofia Papagiannaki
            self.is_active = False
106 18ffbee1 Sofia Papagiannaki
    
107 0905ccd2 Sofia Papagiannaki
    @property
108 0905ccd2 Sofia Papagiannaki
    def realname(self):
109 0905ccd2 Sofia Papagiannaki
        return '%s %s' %(self.first_name, self.last_name)
110 6c736ed7 Kostas Papadimitriou
111 0905ccd2 Sofia Papagiannaki
    @realname.setter
112 0905ccd2 Sofia Papagiannaki
    def realname(self, value):
113 0905ccd2 Sofia Papagiannaki
        parts = value.split(' ')
114 0905ccd2 Sofia Papagiannaki
        if len(parts) == 2:
115 0905ccd2 Sofia Papagiannaki
            self.first_name = parts[0]
116 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[1]
117 0905ccd2 Sofia Papagiannaki
        else:
118 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[0]
119 6c736ed7 Kostas Papadimitriou
120 64cd4730 Antony Chazapis
    @property
121 64cd4730 Antony Chazapis
    def invitation(self):
122 64cd4730 Antony Chazapis
        try:
123 9fb8e808 Sofia Papagiannaki
            return Invitation.objects.get(username=self.email)
124 64cd4730 Antony Chazapis
        except Invitation.DoesNotExist:
125 64cd4730 Antony Chazapis
            return None
126 6c736ed7 Kostas Papadimitriou
127 64cd4730 Antony Chazapis
    def save(self, update_timestamps=True, **kwargs):
128 64cd4730 Antony Chazapis
        if update_timestamps:
129 64cd4730 Antony Chazapis
            if not self.id:
130 0905ccd2 Sofia Papagiannaki
                self.date_joined = datetime.now()
131 64cd4730 Antony Chazapis
            self.updated = datetime.now()
132 18ffbee1 Sofia Papagiannaki
        
133 18ffbee1 Sofia Papagiannaki
        # update date_signed_terms if necessary
134 18ffbee1 Sofia Papagiannaki
        if self.__has_signed_terms != self.has_signed_terms:
135 18ffbee1 Sofia Papagiannaki
            self.date_signed_terms = datetime.now()
136 18ffbee1 Sofia Papagiannaki
        
137 9c01d9d1 Sofia Papagiannaki
        if not self.id:
138 9c01d9d1 Sofia Papagiannaki
            # set username
139 9c01d9d1 Sofia Papagiannaki
            while not self.username:
140 9c01d9d1 Sofia Papagiannaki
                username =  uuid.uuid4().hex[:30]
141 9c01d9d1 Sofia Papagiannaki
                try:
142 9c01d9d1 Sofia Papagiannaki
                    AstakosUser.objects.get(username = username)
143 9c01d9d1 Sofia Papagiannaki
                except AstakosUser.DoesNotExist, e:
144 9c01d9d1 Sofia Papagiannaki
                    self.username = username
145 9c01d9d1 Sofia Papagiannaki
            if not self.provider:
146 9c01d9d1 Sofia Papagiannaki
                self.provider = 'local'
147 9c01d9d1 Sofia Papagiannaki
        report_user_event(self)
148 591d0505 Sofia Papagiannaki
        self.validate_unique_email_isactive()
149 751d24cf Sofia Papagiannaki
        if self.is_active and self.activation_sent:
150 751d24cf Sofia Papagiannaki
            # reset the activation sent
151 751d24cf Sofia Papagiannaki
            self.activation_sent = None
152 0905ccd2 Sofia Papagiannaki
        super(AstakosUser, self).save(**kwargs)
153 18ffbee1 Sofia Papagiannaki
        
154 18ffbee1 Sofia Papagiannaki
        # set group if does not exist
155 18ffbee1 Sofia Papagiannaki
        groupname = 'shibboleth' if self.provider == 'shibboleth' else 'default'
156 18ffbee1 Sofia Papagiannaki
        if groupname not in self.__groupnames:
157 18ffbee1 Sofia Papagiannaki
            try:
158 18ffbee1 Sofia Papagiannaki
                group = Group.objects.get(name = groupname)
159 18ffbee1 Sofia Papagiannaki
                self.groups.add(group)
160 18ffbee1 Sofia Papagiannaki
            except Group.DoesNotExist, e:
161 18ffbee1 Sofia Papagiannaki
                logger.exception(e)
162 64cd4730 Antony Chazapis
    
163 64cd4730 Antony Chazapis
    def renew_token(self):
164 64cd4730 Antony Chazapis
        md5 = hashlib.md5()
165 0905ccd2 Sofia Papagiannaki
        md5.update(self.username)
166 64cd4730 Antony Chazapis
        md5.update(self.realname.encode('ascii', 'ignore'))
167 64cd4730 Antony Chazapis
        md5.update(asctime())
168 6c736ed7 Kostas Papadimitriou
169 64cd4730 Antony Chazapis
        self.auth_token = b64encode(md5.digest())
170 64cd4730 Antony Chazapis
        self.auth_token_created = datetime.now()
171 64cd4730 Antony Chazapis
        self.auth_token_expires = self.auth_token_created + \
172 92defad4 Sofia Papagiannaki
                                  timedelta(hours=AUTH_TOKEN_DURATION)
173 111f3da6 Sofia Papagiannaki
        msg = 'Token renewed for %s' % self.email
174 111f3da6 Sofia Papagiannaki
        logger._log(LOGGING_LEVEL, msg, [])
175 6c736ed7 Kostas Papadimitriou
176 64cd4730 Antony Chazapis
    def __unicode__(self):
177 0905ccd2 Sofia Papagiannaki
        return self.username
178 0a569195 Sofia Papagiannaki
    
179 0a569195 Sofia Papagiannaki
    def conflicting_email(self):
180 0a569195 Sofia Papagiannaki
        q = AstakosUser.objects.exclude(username = self.username)
181 0a569195 Sofia Papagiannaki
        q = q.filter(email = self.email)
182 0a569195 Sofia Papagiannaki
        if q.count() != 0:
183 0a569195 Sofia Papagiannaki
            return True
184 0a569195 Sofia Papagiannaki
        return False
185 0a569195 Sofia Papagiannaki
    
186 591d0505 Sofia Papagiannaki
    def validate_unique_email_isactive(self):
187 0a569195 Sofia Papagiannaki
        """
188 0a569195 Sofia Papagiannaki
        Implements a unique_together constraint for email and is_active fields.
189 0a569195 Sofia Papagiannaki
        """
190 0a569195 Sofia Papagiannaki
        q = AstakosUser.objects.exclude(username = self.username)
191 0a569195 Sofia Papagiannaki
        q = q.filter(email = self.email)
192 0a569195 Sofia Papagiannaki
        q = q.filter(is_active = self.is_active)
193 0a569195 Sofia Papagiannaki
        if q.count() != 0:
194 0a569195 Sofia Papagiannaki
            raise ValidationError({'__all__':[_('Another account with the same email & is_active combination found.')]})
195 09e7393c Sofia Papagiannaki
    
196 09e7393c Sofia Papagiannaki
    def signed_terms(self):
197 09e7393c Sofia Papagiannaki
        term = get_latest_terms()
198 09e7393c Sofia Papagiannaki
        if not term:
199 09e7393c Sofia Papagiannaki
            return True
200 09e7393c Sofia Papagiannaki
        if not self.has_signed_terms:
201 09e7393c Sofia Papagiannaki
            return False
202 09e7393c Sofia Papagiannaki
        if not self.date_signed_terms:
203 09e7393c Sofia Papagiannaki
            return False
204 09e7393c Sofia Papagiannaki
        if self.date_signed_terms < term.date:
205 09e7393c Sofia Papagiannaki
            self.has_signed_terms = False
206 f0f92965 Sofia Papagiannaki
            self.date_signed_terms = None
207 09e7393c Sofia Papagiannaki
            self.save()
208 09e7393c Sofia Papagiannaki
            return False
209 09e7393c Sofia Papagiannaki
        return True
210 09e7393c Sofia Papagiannaki
211 270dd48d Sofia Papagiannaki
class ApprovalTerms(models.Model):
212 270dd48d Sofia Papagiannaki
    """
213 270dd48d Sofia Papagiannaki
    Model for approval terms
214 270dd48d Sofia Papagiannaki
    """
215 6c736ed7 Kostas Papadimitriou
216 270dd48d Sofia Papagiannaki
    date = models.DateTimeField('Issue date', db_index=True, default=datetime.now())
217 270dd48d Sofia Papagiannaki
    location = models.CharField('Terms location', max_length=255)
218 270dd48d Sofia Papagiannaki
219 64cd4730 Antony Chazapis
class Invitation(models.Model):
220 890b0eaf Sofia Papagiannaki
    """
221 890b0eaf Sofia Papagiannaki
    Model for registring invitations
222 890b0eaf Sofia Papagiannaki
    """
223 0905ccd2 Sofia Papagiannaki
    inviter = models.ForeignKey(AstakosUser, related_name='invitations_sent',
224 64cd4730 Antony Chazapis
                                null=True)
225 64cd4730 Antony Chazapis
    realname = models.CharField('Real name', max_length=255)
226 ebd369d0 Sofia Papagiannaki
    username = models.CharField('Unique ID', max_length=255, unique=True)
227 64cd4730 Antony Chazapis
    code = models.BigIntegerField('Invitation code', db_index=True)
228 64cd4730 Antony Chazapis
    is_consumed = models.BooleanField('Consumed?', default=False)
229 64cd4730 Antony Chazapis
    created = models.DateTimeField('Creation date', auto_now_add=True)
230 64cd4730 Antony Chazapis
    consumed = models.DateTimeField('Consumption date', null=True, blank=True)
231 64cd4730 Antony Chazapis
    
232 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
233 18ffbee1 Sofia Papagiannaki
        super(Invitation, self).__init__(*args, **kwargs)
234 8f5a3a06 Sofia Papagiannaki
        if not self.id:
235 8f5a3a06 Sofia Papagiannaki
            self.code = _generate_invitation_code()
236 8f5a3a06 Sofia Papagiannaki
    
237 64cd4730 Antony Chazapis
    def consume(self):
238 64cd4730 Antony Chazapis
        self.is_consumed = True
239 64cd4730 Antony Chazapis
        self.consumed = datetime.now()
240 64cd4730 Antony Chazapis
        self.save()
241 6c736ed7 Kostas Papadimitriou
242 64cd4730 Antony Chazapis
    def __unicode__(self):
243 0905ccd2 Sofia Papagiannaki
        return '%s -> %s [%d]' % (self.inviter, self.username, self.code)
244 9c01d9d1 Sofia Papagiannaki
245 9c01d9d1 Sofia Papagiannaki
def report_user_event(user):
246 9c01d9d1 Sofia Papagiannaki
    def should_send(user):
247 9c01d9d1 Sofia Papagiannaki
        # report event incase of new user instance
248 9c01d9d1 Sofia Papagiannaki
        # or if specific fields are modified
249 9c01d9d1 Sofia Papagiannaki
        if not user.id:
250 9c01d9d1 Sofia Papagiannaki
            return True
251 9c01d9d1 Sofia Papagiannaki
        db_instance = AstakosUser.objects.get(id = user.id)
252 9c01d9d1 Sofia Papagiannaki
        for f in BILLING_FIELDS:
253 9c01d9d1 Sofia Papagiannaki
            if (db_instance.__getattribute__(f) != user.__getattribute__(f)):
254 9c01d9d1 Sofia Papagiannaki
                return True
255 9c01d9d1 Sofia Papagiannaki
        return False
256 6c736ed7 Kostas Papadimitriou
257 3a9f4931 Sofia Papagiannaki
    if QUEUE_CONNECTION and should_send(user):
258 6c736ed7 Kostas Papadimitriou
259 6c736ed7 Kostas Papadimitriou
        from astakos.im.queue.userevent import UserEvent
260 6c736ed7 Kostas Papadimitriou
        from synnefo.lib.queue import exchange_connect, exchange_send, \
261 6c736ed7 Kostas Papadimitriou
                exchange_close
262 6c736ed7 Kostas Papadimitriou
263 59f598f1 Sofia Papagiannaki
        eventType = 'create' if not user.id else 'modify'
264 59f598f1 Sofia Papagiannaki
        body = UserEvent(QUEUE_CLIENT_ID, user, eventType, {}).format()
265 3a9f4931 Sofia Papagiannaki
        conn = exchange_connect(QUEUE_CONNECTION)
266 9e19989d Sofia Papagiannaki
        parts = urlparse(QUEUE_CONNECTION)
267 270dd48d Sofia Papagiannaki
        exchange = parts.path[1:]
268 270dd48d Sofia Papagiannaki
        routing_key = '%s.user' % exchange
269 9c01d9d1 Sofia Papagiannaki
        exchange_send(conn, routing_key, body)
270 68cb6899 Sofia Papagiannaki
        exchange_close(conn)
271 8f5a3a06 Sofia Papagiannaki
272 8f5a3a06 Sofia Papagiannaki
def _generate_invitation_code():
273 8f5a3a06 Sofia Papagiannaki
    while True:
274 8f5a3a06 Sofia Papagiannaki
        code = randint(1, 2L**63 - 1)
275 8f5a3a06 Sofia Papagiannaki
        try:
276 8f5a3a06 Sofia Papagiannaki
            Invitation.objects.get(code=code)
277 8f5a3a06 Sofia Papagiannaki
            # An invitation with this code already exists, try again
278 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
279 09e7393c Sofia Papagiannaki
            return code
280 09e7393c Sofia Papagiannaki
281 09e7393c Sofia Papagiannaki
def get_latest_terms():
282 09e7393c Sofia Papagiannaki
    try:
283 09e7393c Sofia Papagiannaki
        term = ApprovalTerms.objects.order_by('-id')[0]
284 09e7393c Sofia Papagiannaki
        return term
285 09e7393c Sofia Papagiannaki
    except IndexError:
286 09e7393c Sofia Papagiannaki
        pass
287 49790d9d Sofia Papagiannaki
    return None
288 49790d9d Sofia Papagiannaki
289 49790d9d Sofia Papagiannaki
class EmailChangeManager(models.Manager):
290 49790d9d Sofia Papagiannaki
    @transaction.commit_on_success
291 49790d9d Sofia Papagiannaki
    def change_email(self, activation_key):
292 49790d9d Sofia Papagiannaki
        """
293 49790d9d Sofia Papagiannaki
        Validate an activation key and change the corresponding
294 49790d9d Sofia Papagiannaki
        ``User`` if valid.
295 49790d9d Sofia Papagiannaki

296 49790d9d Sofia Papagiannaki
        If the key is valid and has not expired, return the ``User``
297 49790d9d Sofia Papagiannaki
        after activating.
298 49790d9d Sofia Papagiannaki

299 49790d9d Sofia Papagiannaki
        If the key is not valid or has expired, return ``None``.
300 49790d9d Sofia Papagiannaki

301 49790d9d Sofia Papagiannaki
        If the key is valid but the ``User`` is already active,
302 49790d9d Sofia Papagiannaki
        return ``None``.
303 49790d9d Sofia Papagiannaki

304 49790d9d Sofia Papagiannaki
        After successful email change the activation record is deleted.
305 49790d9d Sofia Papagiannaki

306 49790d9d Sofia Papagiannaki
        Throws ValueError if there is already
307 49790d9d Sofia Papagiannaki
        """
308 49790d9d Sofia Papagiannaki
        try:
309 49790d9d Sofia Papagiannaki
            email_change = self.model.objects.get(activation_key=activation_key)
310 49790d9d Sofia Papagiannaki
            if email_change.activation_key_expired():
311 49790d9d Sofia Papagiannaki
                email_change.delete()
312 49790d9d Sofia Papagiannaki
                raise EmailChange.DoesNotExist
313 49790d9d Sofia Papagiannaki
            # is there an active user with this address?
314 49790d9d Sofia Papagiannaki
            try:
315 49790d9d Sofia Papagiannaki
                AstakosUser.objects.get(email=email_change.new_email_address)
316 49790d9d Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
317 49790d9d Sofia Papagiannaki
                pass
318 49790d9d Sofia Papagiannaki
            else:
319 49790d9d Sofia Papagiannaki
                raise ValueError(_('The new email address is reserved.'))
320 49790d9d Sofia Papagiannaki
            # update user
321 49790d9d Sofia Papagiannaki
            user = AstakosUser.objects.get(pk=email_change.user_id)
322 49790d9d Sofia Papagiannaki
            user.email = email_change.new_email_address
323 49790d9d Sofia Papagiannaki
            user.save()
324 49790d9d Sofia Papagiannaki
            email_change.delete()
325 49790d9d Sofia Papagiannaki
            return user
326 49790d9d Sofia Papagiannaki
        except EmailChange.DoesNotExist:
327 49790d9d Sofia Papagiannaki
            raise ValueError(_('Invalid activation key'))
328 49790d9d Sofia Papagiannaki
329 49790d9d Sofia Papagiannaki
class EmailChange(models.Model):
330 49790d9d Sofia Papagiannaki
    new_email_address = models.EmailField(_(u'new e-mail address'), help_text=_(u'Your old email address will be used until you verify your new one.'))
331 49790d9d Sofia Papagiannaki
    user = models.ForeignKey(AstakosUser, unique=True, related_name='emailchange_user')
332 49790d9d Sofia Papagiannaki
    requested_at = models.DateTimeField(default=datetime.now())
333 49790d9d Sofia Papagiannaki
    activation_key = models.CharField(max_length=40, unique=True, db_index=True)
334 49790d9d Sofia Papagiannaki
335 49790d9d Sofia Papagiannaki
    objects = EmailChangeManager()
336 49790d9d Sofia Papagiannaki
337 49790d9d Sofia Papagiannaki
    def activation_key_expired(self):
338 49790d9d Sofia Papagiannaki
        expiration_date = timedelta(days=EMAILCHANGE_ACTIVATION_DAYS)
339 ff9290ec Sofia Papagiannaki
        return self.requested_at + expiration_date < datetime.now()
340 ff9290ec Sofia Papagiannaki
341 6b03a847 Sofia Papagiannaki
class Service(models.Model):
342 6b03a847 Sofia Papagiannaki
    name = models.CharField('Name', max_length=255, unique=True)
343 6b03a847 Sofia Papagiannaki
    url = models.FilePathField()
344 6b03a847 Sofia Papagiannaki
    icon = models.FilePathField(blank=True)
345 6b03a847 Sofia Papagiannaki
    auth_token = models.CharField('Authentication Token', max_length=32,
346 6b03a847 Sofia Papagiannaki
                                  null=True, blank=True)
347 6b03a847 Sofia Papagiannaki
    auth_token_created = models.DateTimeField('Token creation date', null=True)
348 6b03a847 Sofia Papagiannaki
    auth_token_expires = models.DateTimeField('Token expiration date', null=True)
349 6b03a847 Sofia Papagiannaki
    
350 6b03a847 Sofia Papagiannaki
    def save(self, **kwargs):
351 6b03a847 Sofia Papagiannaki
        if not self.id:
352 6b03a847 Sofia Papagiannaki
            self.renew_token()
353 6b03a847 Sofia Papagiannaki
        self.full_clean()
354 6b03a847 Sofia Papagiannaki
        super(Service, self).save(**kwargs)
355 6b03a847 Sofia Papagiannaki
    
356 6b03a847 Sofia Papagiannaki
    def renew_token(self):
357 6b03a847 Sofia Papagiannaki
        md5 = hashlib.md5()
358 6b03a847 Sofia Papagiannaki
        md5.update(self.name.encode('ascii', 'ignore'))
359 6b03a847 Sofia Papagiannaki
        md5.update(self.url.encode('ascii', 'ignore'))
360 6b03a847 Sofia Papagiannaki
        md5.update(asctime())
361 6b03a847 Sofia Papagiannaki
362 6b03a847 Sofia Papagiannaki
        self.auth_token = b64encode(md5.digest())
363 6b03a847 Sofia Papagiannaki
        self.auth_token_created = datetime.now()
364 6b03a847 Sofia Papagiannaki
        self.auth_token_expires = self.auth_token_created + \
365 6b03a847 Sofia Papagiannaki
                                  timedelta(hours=AUTH_TOKEN_DURATION)
366 6b03a847 Sofia Papagiannaki
367 ca828a10 Sofia Papagiannaki
class AdditionalMail(models.Model):
368 ca828a10 Sofia Papagiannaki
    """
369 ca828a10 Sofia Papagiannaki
    Model for registring invitations
370 ca828a10 Sofia Papagiannaki
    """
371 ca828a10 Sofia Papagiannaki
    owner = models.ForeignKey(AstakosUser)
372 ca828a10 Sofia Papagiannaki
    email = models.EmailField(unique=True)
373 ca828a10 Sofia Papagiannaki
374 ff9290ec Sofia Papagiannaki
def create_astakos_user(u):
375 ff9290ec Sofia Papagiannaki
    try:
376 ff9290ec Sofia Papagiannaki
        AstakosUser.objects.get(user_ptr=u.pk)
377 ff9290ec Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
378 ff9290ec Sofia Papagiannaki
        extended_user = AstakosUser(user_ptr_id=u.pk)
379 ff9290ec Sofia Papagiannaki
        extended_user.__dict__.update(u.__dict__)
380 ff9290ec Sofia Papagiannaki
        extended_user.renew_token()
381 ff9290ec Sofia Papagiannaki
        extended_user.save()
382 ff9290ec Sofia Papagiannaki
    except:
383 ff9290ec Sofia Papagiannaki
        pass
384 ff9290ec Sofia Papagiannaki
385 ff9290ec Sofia Papagiannaki
def superuser_post_syncdb(sender, **kwargs):
386 ff9290ec Sofia Papagiannaki
    # if there was created a superuser
387 ff9290ec Sofia Papagiannaki
    # associate it with an AstakosUser
388 ff9290ec Sofia Papagiannaki
    admins = User.objects.filter(is_superuser=True)
389 ff9290ec Sofia Papagiannaki
    for u in admins:
390 ff9290ec Sofia Papagiannaki
        create_astakos_user(u)
391 ff9290ec Sofia Papagiannaki
392 ff9290ec Sofia Papagiannaki
post_syncdb.connect(superuser_post_syncdb)
393 ff9290ec Sofia Papagiannaki
394 ff9290ec Sofia Papagiannaki
def superuser_post_save(sender, instance, **kwargs):
395 ff9290ec Sofia Papagiannaki
    if instance.is_superuser:
396 ff9290ec Sofia Papagiannaki
        create_astakos_user(instance)
397 ff9290ec Sofia Papagiannaki
398 ff9290ec Sofia Papagiannaki
post_save.connect(superuser_post_save, sender=User)