Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / models.py @ 9e19989d

History | View | Annotate | Download (7.4 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
37 64cd4730 Antony Chazapis
from time import asctime
38 64cd4730 Antony Chazapis
from datetime import datetime, timedelta
39 64cd4730 Antony Chazapis
from base64 import b64encode
40 4c0174a9 Sofia Papagiannaki
from urlparse import urlparse
41 64cd4730 Antony Chazapis
42 64cd4730 Antony Chazapis
from django.db import models
43 0905ccd2 Sofia Papagiannaki
from django.contrib.auth.models import User, UserManager
44 64cd4730 Antony Chazapis
45 3a9f4931 Sofia Papagiannaki
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_CONNECTION
46 59f598f1 Sofia Papagiannaki
from astakos.im.queue.userevent import UserEvent
47 9c01d9d1 Sofia Papagiannaki
from synnefo.lib.queue import exchange_connect, exchange_send, exchange_close, Receipt
48 9c01d9d1 Sofia Papagiannaki
49 9c01d9d1 Sofia Papagiannaki
QUEUE_CLIENT_ID = 3 # Astakos.
50 64cd4730 Antony Chazapis
51 0905ccd2 Sofia Papagiannaki
class AstakosUser(User):
52 890b0eaf Sofia Papagiannaki
    """
53 890b0eaf Sofia Papagiannaki
    Extends ``django.contrib.auth.models.User`` by defining additional fields.
54 890b0eaf Sofia Papagiannaki
    """
55 0905ccd2 Sofia Papagiannaki
    # Use UserManager to get the create_user method, etc.
56 0905ccd2 Sofia Papagiannaki
    objects = UserManager()
57 64cd4730 Antony Chazapis
    
58 5ed6816e Sofia Papagiannaki
    affiliation = models.CharField('Affiliation', max_length=255, blank=True)
59 5ed6816e Sofia Papagiannaki
    provider = models.CharField('Provider', max_length=255, blank=True)
60 64cd4730 Antony Chazapis
    
61 64cd4730 Antony Chazapis
    #for invitations
62 92defad4 Sofia Papagiannaki
    user_level = DEFAULT_USER_LEVEL
63 a196eb7e Sofia Papagiannaki
    level = models.IntegerField('Inviter level', default=user_level)
64 ebd369d0 Sofia Papagiannaki
    invitations = models.IntegerField('Invitations left', default=INVITATIONS_PER_LEVEL.get(user_level, 0))
65 64cd4730 Antony Chazapis
    
66 64cd4730 Antony Chazapis
    auth_token = models.CharField('Authentication Token', max_length=32,
67 0905ccd2 Sofia Papagiannaki
                                  null=True, blank=True)
68 0905ccd2 Sofia Papagiannaki
    auth_token_created = models.DateTimeField('Token creation date', null=True)
69 0905ccd2 Sofia Papagiannaki
    auth_token_expires = models.DateTimeField('Token expiration date', null=True)
70 64cd4730 Antony Chazapis
    
71 64cd4730 Antony Chazapis
    updated = models.DateTimeField('Update date')
72 890b0eaf Sofia Papagiannaki
    is_verified = models.BooleanField('Is verified?', default=False)
73 64cd4730 Antony Chazapis
    
74 15efc749 Sofia Papagiannaki
    # ex. screen_name for twitter, eppn for shibboleth
75 15efc749 Sofia Papagiannaki
    third_party_identifier = models.CharField('Third-party identifier', max_length=255, null=True, blank=True)
76 15efc749 Sofia Papagiannaki
    
77 ebd369d0 Sofia Papagiannaki
    email_verified = models.BooleanField('Email verified?', default=False)
78 ebd369d0 Sofia Papagiannaki
    
79 59f598f1 Sofia Papagiannaki
    has_credits = models.BooleanField('Has credits?', default=False)
80 270dd48d Sofia Papagiannaki
    has_signed_terms = models.BooleanField('Agree with the terms?', default=False)
81 270dd48d Sofia Papagiannaki
    date_signed_terms = models.DateTimeField('Signed terms date', null=True)
82 59f598f1 Sofia Papagiannaki
    
83 0905ccd2 Sofia Papagiannaki
    @property
84 0905ccd2 Sofia Papagiannaki
    def realname(self):
85 0905ccd2 Sofia Papagiannaki
        return '%s %s' %(self.first_name, self.last_name)
86 64cd4730 Antony Chazapis
    
87 0905ccd2 Sofia Papagiannaki
    @realname.setter
88 0905ccd2 Sofia Papagiannaki
    def realname(self, value):
89 0905ccd2 Sofia Papagiannaki
        parts = value.split(' ')
90 0905ccd2 Sofia Papagiannaki
        if len(parts) == 2:
91 0905ccd2 Sofia Papagiannaki
            self.first_name = parts[0]
92 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[1]
93 0905ccd2 Sofia Papagiannaki
        else:
94 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[0]
95 64cd4730 Antony Chazapis
    
96 64cd4730 Antony Chazapis
    @property
97 64cd4730 Antony Chazapis
    def invitation(self):
98 64cd4730 Antony Chazapis
        try:
99 9fb8e808 Sofia Papagiannaki
            return Invitation.objects.get(username=self.email)
100 64cd4730 Antony Chazapis
        except Invitation.DoesNotExist:
101 64cd4730 Antony Chazapis
            return None
102 64cd4730 Antony Chazapis
    
103 64cd4730 Antony Chazapis
    def save(self, update_timestamps=True, **kwargs):
104 64cd4730 Antony Chazapis
        if update_timestamps:
105 64cd4730 Antony Chazapis
            if not self.id:
106 0905ccd2 Sofia Papagiannaki
                self.date_joined = datetime.now()
107 64cd4730 Antony Chazapis
            self.updated = datetime.now()
108 9c01d9d1 Sofia Papagiannaki
        if not self.id:
109 9c01d9d1 Sofia Papagiannaki
            # set username
110 9c01d9d1 Sofia Papagiannaki
            while not self.username:
111 9c01d9d1 Sofia Papagiannaki
                username =  uuid.uuid4().hex[:30]
112 9c01d9d1 Sofia Papagiannaki
                try:
113 9c01d9d1 Sofia Papagiannaki
                    AstakosUser.objects.get(username = username)
114 9c01d9d1 Sofia Papagiannaki
                except AstakosUser.DoesNotExist, e:
115 9c01d9d1 Sofia Papagiannaki
                    self.username = username
116 9c01d9d1 Sofia Papagiannaki
            self.is_active = False
117 9c01d9d1 Sofia Papagiannaki
            if not self.provider:
118 9c01d9d1 Sofia Papagiannaki
                self.provider = 'local'
119 9c01d9d1 Sofia Papagiannaki
        report_user_event(self)
120 0905ccd2 Sofia Papagiannaki
        super(AstakosUser, self).save(**kwargs)
121 64cd4730 Antony Chazapis
    
122 64cd4730 Antony Chazapis
    def renew_token(self):
123 64cd4730 Antony Chazapis
        md5 = hashlib.md5()
124 0905ccd2 Sofia Papagiannaki
        md5.update(self.username)
125 64cd4730 Antony Chazapis
        md5.update(self.realname.encode('ascii', 'ignore'))
126 64cd4730 Antony Chazapis
        md5.update(asctime())
127 64cd4730 Antony Chazapis
        
128 64cd4730 Antony Chazapis
        self.auth_token = b64encode(md5.digest())
129 64cd4730 Antony Chazapis
        self.auth_token_created = datetime.now()
130 64cd4730 Antony Chazapis
        self.auth_token_expires = self.auth_token_created + \
131 92defad4 Sofia Papagiannaki
                                  timedelta(hours=AUTH_TOKEN_DURATION)
132 64cd4730 Antony Chazapis
    
133 64cd4730 Antony Chazapis
    def __unicode__(self):
134 0905ccd2 Sofia Papagiannaki
        return self.username
135 64cd4730 Antony Chazapis
136 270dd48d Sofia Papagiannaki
class ApprovalTerms(models.Model):
137 270dd48d Sofia Papagiannaki
    """
138 270dd48d Sofia Papagiannaki
    Model for approval terms
139 270dd48d Sofia Papagiannaki
    """
140 270dd48d Sofia Papagiannaki
    
141 270dd48d Sofia Papagiannaki
    date = models.DateTimeField('Issue date', db_index=True, default=datetime.now())
142 270dd48d Sofia Papagiannaki
    location = models.CharField('Terms location', max_length=255)
143 270dd48d Sofia Papagiannaki
144 64cd4730 Antony Chazapis
class Invitation(models.Model):
145 890b0eaf Sofia Papagiannaki
    """
146 890b0eaf Sofia Papagiannaki
    Model for registring invitations
147 890b0eaf Sofia Papagiannaki
    """
148 0905ccd2 Sofia Papagiannaki
    inviter = models.ForeignKey(AstakosUser, related_name='invitations_sent',
149 64cd4730 Antony Chazapis
                                null=True)
150 64cd4730 Antony Chazapis
    realname = models.CharField('Real name', max_length=255)
151 ebd369d0 Sofia Papagiannaki
    username = models.CharField('Unique ID', max_length=255, unique=True)
152 64cd4730 Antony Chazapis
    code = models.BigIntegerField('Invitation code', db_index=True)
153 64cd4730 Antony Chazapis
    #obsolete: we keep it just for transfering the data
154 64cd4730 Antony Chazapis
    is_accepted = models.BooleanField('Accepted?', default=False)
155 64cd4730 Antony Chazapis
    is_consumed = models.BooleanField('Consumed?', default=False)
156 64cd4730 Antony Chazapis
    created = models.DateTimeField('Creation date', auto_now_add=True)
157 64cd4730 Antony Chazapis
    #obsolete: we keep it just for transfering the data
158 64cd4730 Antony Chazapis
    accepted = models.DateTimeField('Acceptance date', null=True, blank=True)
159 64cd4730 Antony Chazapis
    consumed = models.DateTimeField('Consumption date', null=True, blank=True)
160 64cd4730 Antony Chazapis
    
161 64cd4730 Antony Chazapis
    def consume(self):
162 64cd4730 Antony Chazapis
        self.is_consumed = True
163 64cd4730 Antony Chazapis
        self.consumed = datetime.now()
164 64cd4730 Antony Chazapis
        self.save()
165 64cd4730 Antony Chazapis
        
166 64cd4730 Antony Chazapis
    def __unicode__(self):
167 0905ccd2 Sofia Papagiannaki
        return '%s -> %s [%d]' % (self.inviter, self.username, self.code)
168 9c01d9d1 Sofia Papagiannaki
169 9c01d9d1 Sofia Papagiannaki
def report_user_event(user):
170 9c01d9d1 Sofia Papagiannaki
    def should_send(user):
171 9c01d9d1 Sofia Papagiannaki
        # report event incase of new user instance
172 9c01d9d1 Sofia Papagiannaki
        # or if specific fields are modified
173 9c01d9d1 Sofia Papagiannaki
        if not user.id:
174 9c01d9d1 Sofia Papagiannaki
            return True
175 9c01d9d1 Sofia Papagiannaki
        db_instance = AstakosUser.objects.get(id = user.id)
176 9c01d9d1 Sofia Papagiannaki
        for f in BILLING_FIELDS:
177 9c01d9d1 Sofia Papagiannaki
            if (db_instance.__getattribute__(f) != user.__getattribute__(f)):
178 9c01d9d1 Sofia Papagiannaki
                return True
179 9c01d9d1 Sofia Papagiannaki
        return False
180 9c01d9d1 Sofia Papagiannaki
    
181 3a9f4931 Sofia Papagiannaki
    if QUEUE_CONNECTION and should_send(user):
182 59f598f1 Sofia Papagiannaki
        eventType = 'create' if not user.id else 'modify'
183 59f598f1 Sofia Papagiannaki
        body = UserEvent(QUEUE_CLIENT_ID, user, eventType, {}).format()
184 3a9f4931 Sofia Papagiannaki
        conn = exchange_connect(QUEUE_CONNECTION)
185 9e19989d Sofia Papagiannaki
        parts = urlparse(QUEUE_CONNECTION)
186 270dd48d Sofia Papagiannaki
        exchange = parts.path[1:]
187 270dd48d Sofia Papagiannaki
        routing_key = '%s.user' % exchange
188 9c01d9d1 Sofia Papagiannaki
        exchange_send(conn, routing_key, body)
189 68cb6899 Sofia Papagiannaki
        exchange_close(conn)