Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (22.3 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 64cd4730 Antony Chazapis
38 64cd4730 Antony Chazapis
from time import asctime
39 64cd4730 Antony Chazapis
from datetime import datetime, timedelta
40 64cd4730 Antony Chazapis
from base64 import b64encode
41 8f5a3a06 Sofia Papagiannaki
from random import randint
42 ffb1e7a8 Sofia Papagiannaki
from collections import defaultdict
43 64cd4730 Antony Chazapis
44 aab4d540 Sofia Papagiannaki
from django.db import models
45 18ffbee1 Sofia Papagiannaki
from django.contrib.auth.models import User, UserManager, Group
46 0a569195 Sofia Papagiannaki
from django.utils.translation import ugettext as _
47 0a569195 Sofia Papagiannaki
from django.core.exceptions import ValidationError
48 49790d9d Sofia Papagiannaki
from django.db import transaction
49 29816137 Sofia Papagiannaki
from django.db.models.signals import (pre_save, post_save, post_syncdb,
50 29816137 Sofia Papagiannaki
                                      post_delete)
51 fc1e2f02 Sofia Papagiannaki
from django.dispatch import Signal
52 aab4d540 Sofia Papagiannaki
from django.db.models import Q
53 64cd4730 Antony Chazapis
54 fc1e2f02 Sofia Papagiannaki
from astakos.im.settings import (DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL,
55 bd4f356c Sofia Papagiannaki
                                 AUTH_TOKEN_DURATION, BILLING_FIELDS,
56 bd4f356c Sofia Papagiannaki
                                 EMAILCHANGE_ACTIVATION_DAYS, LOGGING_LEVEL)
57 bd4f356c Sofia Papagiannaki
from astakos.im.endpoints.quotaholder import (register_users, send_quota,
58 bd4f356c Sofia Papagiannaki
                                              register_resources)
59 fc1e2f02 Sofia Papagiannaki
from astakos.im.endpoints.aquarium.producer import report_user_event
60 9c01d9d1 Sofia Papagiannaki
61 fc1e2f02 Sofia Papagiannaki
from astakos.im.tasks import propagate_groupmembers_quota
62 64cd4730 Antony Chazapis
63 18ffbee1 Sofia Papagiannaki
logger = logging.getLogger(__name__)
64 18ffbee1 Sofia Papagiannaki
65 5ce3ce4f Sofia Papagiannaki
66 8e45d6fd Sofia Papagiannaki
class Service(models.Model):
67 8e45d6fd Sofia Papagiannaki
    name = models.CharField('Name', max_length=255, unique=True, db_index=True)
68 8e45d6fd Sofia Papagiannaki
    url = models.FilePathField()
69 8e45d6fd Sofia Papagiannaki
    icon = models.FilePathField(blank=True)
70 8e45d6fd Sofia Papagiannaki
    auth_token = models.CharField('Authentication Token', max_length=32,
71 8e45d6fd Sofia Papagiannaki
                                  null=True, blank=True)
72 8e45d6fd Sofia Papagiannaki
    auth_token_created = models.DateTimeField('Token creation date', null=True)
73 5ce3ce4f Sofia Papagiannaki
    auth_token_expires = models.DateTimeField(
74 5ce3ce4f Sofia Papagiannaki
        'Token expiration date', null=True)
75 5ce3ce4f Sofia Papagiannaki
76 8e45d6fd Sofia Papagiannaki
    def save(self, **kwargs):
77 8e45d6fd Sofia Papagiannaki
        if not self.id:
78 8e45d6fd Sofia Papagiannaki
            self.renew_token()
79 8e45d6fd Sofia Papagiannaki
        self.full_clean()
80 8e45d6fd Sofia Papagiannaki
        super(Service, self).save(**kwargs)
81 5ce3ce4f Sofia Papagiannaki
82 8e45d6fd Sofia Papagiannaki
    def renew_token(self):
83 8e45d6fd Sofia Papagiannaki
        md5 = hashlib.md5()
84 8e45d6fd Sofia Papagiannaki
        md5.update(self.name.encode('ascii', 'ignore'))
85 8e45d6fd Sofia Papagiannaki
        md5.update(self.url.encode('ascii', 'ignore'))
86 8e45d6fd Sofia Papagiannaki
        md5.update(asctime())
87 8e45d6fd Sofia Papagiannaki
88 8e45d6fd Sofia Papagiannaki
        self.auth_token = b64encode(md5.digest())
89 8e45d6fd Sofia Papagiannaki
        self.auth_token_created = datetime.now()
90 8e45d6fd Sofia Papagiannaki
        self.auth_token_expires = self.auth_token_created + \
91 5ce3ce4f Sofia Papagiannaki
            timedelta(hours=AUTH_TOKEN_DURATION)
92 5ce3ce4f Sofia Papagiannaki
93 8e45d6fd Sofia Papagiannaki
    def __str__(self):
94 8e45d6fd Sofia Papagiannaki
        return self.name
95 8e45d6fd Sofia Papagiannaki
96 5ce3ce4f Sofia Papagiannaki
97 8e45d6fd Sofia Papagiannaki
class ResourceMetadata(models.Model):
98 8e45d6fd Sofia Papagiannaki
    key = models.CharField('Name', max_length=255, unique=True, db_index=True)
99 8e45d6fd Sofia Papagiannaki
    value = models.CharField('Value', max_length=255)
100 8e45d6fd Sofia Papagiannaki
101 5ce3ce4f Sofia Papagiannaki
102 8e45d6fd Sofia Papagiannaki
class Resource(models.Model):
103 8e45d6fd Sofia Papagiannaki
    name = models.CharField('Name', max_length=255, unique=True, db_index=True)
104 8e45d6fd Sofia Papagiannaki
    meta = models.ManyToManyField(ResourceMetadata)
105 8e45d6fd Sofia Papagiannaki
    service = models.ForeignKey(Service)
106 5ce3ce4f Sofia Papagiannaki
107 8e45d6fd Sofia Papagiannaki
    def __str__(self):
108 0f42ee35 Sofia Papagiannaki
        return '%s.%s' % (self.service, self.name)
109 8e45d6fd Sofia Papagiannaki
110 5ce3ce4f Sofia Papagiannaki
111 8e45d6fd Sofia Papagiannaki
class GroupKind(models.Model):
112 8e45d6fd Sofia Papagiannaki
    name = models.CharField('Name', max_length=255, unique=True, db_index=True)
113 5ce3ce4f Sofia Papagiannaki
114 8e45d6fd Sofia Papagiannaki
    def __str__(self):
115 8e45d6fd Sofia Papagiannaki
        return self.name
116 8e45d6fd Sofia Papagiannaki
117 5ce3ce4f Sofia Papagiannaki
118 8e45d6fd Sofia Papagiannaki
class AstakosGroup(Group):
119 8e45d6fd Sofia Papagiannaki
    kind = models.ForeignKey(GroupKind)
120 2b1a5f5d Olga Brani
    homepage = models.URLField(
121 2b1a5f5d Olga Brani
        'Homepage Url', max_length=255, null=True, blank=True)
122 8e45d6fd Sofia Papagiannaki
    desc = models.TextField('Description', null=True)
123 fc1e2f02 Sofia Papagiannaki
    policy = models.ManyToManyField(Resource, null=True, blank=True,
124 661c4479 Sofia Papagiannaki
                                    through='AstakosGroupQuota')
125 fc1e2f02 Sofia Papagiannaki
    creation_date = models.DateTimeField('Creation date',
126 661c4479 Sofia Papagiannaki
                                         default=datetime.now())
127 8e45d6fd Sofia Papagiannaki
    issue_date = models.DateTimeField('Issue date', null=True)
128 8e45d6fd Sofia Papagiannaki
    expiration_date = models.DateTimeField('Expiration date', null=True)
129 fc1e2f02 Sofia Papagiannaki
    moderation_enabled = models.BooleanField('Moderated membership?',
130 661c4479 Sofia Papagiannaki
                                             default=True)
131 fc1e2f02 Sofia Papagiannaki
    approval_date = models.DateTimeField('Activation date', null=True,
132 661c4479 Sofia Papagiannaki
                                         blank=True)
133 fc1e2f02 Sofia Papagiannaki
    estimated_participants = models.PositiveIntegerField('Estimated #members',
134 661c4479 Sofia Papagiannaki
                                                         null=True)
135 5ce3ce4f Sofia Papagiannaki
136 8e45d6fd Sofia Papagiannaki
    @property
137 8e45d6fd Sofia Papagiannaki
    def is_disabled(self):
138 ffb1e7a8 Sofia Papagiannaki
        if not self.approval_date:
139 ffb1e7a8 Sofia Papagiannaki
            return True
140 ffb1e7a8 Sofia Papagiannaki
        return False
141 5ce3ce4f Sofia Papagiannaki
142 8e45d6fd Sofia Papagiannaki
    @property
143 ffb1e7a8 Sofia Papagiannaki
    def is_enabled(self):
144 8e45d6fd Sofia Papagiannaki
        if self.is_disabled:
145 8e45d6fd Sofia Papagiannaki
            return False
146 8e45d6fd Sofia Papagiannaki
        if not self.issue_date:
147 8e45d6fd Sofia Papagiannaki
            return False
148 8e45d6fd Sofia Papagiannaki
        if not self.expiration_date:
149 8e45d6fd Sofia Papagiannaki
            return True
150 8e45d6fd Sofia Papagiannaki
        now = datetime.now()
151 8e45d6fd Sofia Papagiannaki
        if self.issue_date > now:
152 8e45d6fd Sofia Papagiannaki
            return False
153 8e45d6fd Sofia Papagiannaki
        if now >= self.expiration_date:
154 8e45d6fd Sofia Papagiannaki
            return False
155 8e45d6fd Sofia Papagiannaki
        return True
156 5ce3ce4f Sofia Papagiannaki
157 ffb1e7a8 Sofia Papagiannaki
    def enable(self):
158 fc1e2f02 Sofia Papagiannaki
        if self.is_enabled:
159 fc1e2f02 Sofia Papagiannaki
            return
160 8e45d6fd Sofia Papagiannaki
        self.approval_date = datetime.now()
161 8e45d6fd Sofia Papagiannaki
        self.save()
162 20d50182 Sofia Papagiannaki
        quota_disturbed.send(sender=self, users=self.approved_members)
163 5ce3ce4f Sofia Papagiannaki
        propagate_groupmembers_quota.apply_async(
164 5ce3ce4f Sofia Papagiannaki
            args=[self], eta=self.issue_date)
165 5ce3ce4f Sofia Papagiannaki
        propagate_groupmembers_quota.apply_async(
166 5ce3ce4f Sofia Papagiannaki
            args=[self], eta=self.expiration_date)
167 5ce3ce4f Sofia Papagiannaki
168 ffb1e7a8 Sofia Papagiannaki
    def disable(self):
169 fc1e2f02 Sofia Papagiannaki
        if self.is_disabled:
170 fc1e2f02 Sofia Papagiannaki
            return
171 8e45d6fd Sofia Papagiannaki
        self.approval_date = None
172 8e45d6fd Sofia Papagiannaki
        self.save()
173 fc1e2f02 Sofia Papagiannaki
        quota_disturbed.send(sender=self, users=self.approved_members)
174 5ce3ce4f Sofia Papagiannaki
175 01ac12d5 Sofia Papagiannaki
    def approve_member(self, person):
176 0f4fa26d Sofia Papagiannaki
        m, created = self.membership_set.get_or_create(person=person)
177 0f4fa26d Sofia Papagiannaki
        # update date_joined in any case
178 5ce3ce4f Sofia Papagiannaki
        m.date_joined = datetime.now()
179 0f4fa26d Sofia Papagiannaki
        m.save()
180 5ce3ce4f Sofia Papagiannaki
181 01ac12d5 Sofia Papagiannaki
    def disapprove_member(self, person):
182 01ac12d5 Sofia Papagiannaki
        self.membership_set.remove(person=person)
183 5ce3ce4f Sofia Papagiannaki
184 01ac12d5 Sofia Papagiannaki
    @property
185 01ac12d5 Sofia Papagiannaki
    def members(self):
186 032ade79 Sofia Papagiannaki
        q = self.membership_set.select_related().all()
187 032ade79 Sofia Papagiannaki
        return [m.person for m in q]
188 5ce3ce4f Sofia Papagiannaki
189 01ac12d5 Sofia Papagiannaki
    @property
190 01ac12d5 Sofia Papagiannaki
    def approved_members(self):
191 032ade79 Sofia Papagiannaki
        q = self.membership_set.select_related().all()
192 032ade79 Sofia Papagiannaki
        return [m.person for m in q if m.is_approved]
193 5ce3ce4f Sofia Papagiannaki
194 01ac12d5 Sofia Papagiannaki
    @property
195 ffb1e7a8 Sofia Papagiannaki
    def quota(self):
196 0f4fa26d Sofia Papagiannaki
        d = defaultdict(int)
197 dfdc64d2 Sofia Papagiannaki
        for q in self.astakosgroupquota_set.select_related().all():
198 670de92a Sofia Papagiannaki
            d[q.resource] += q.uplimit
199 ffb1e7a8 Sofia Papagiannaki
        return d
200 5ce3ce4f Sofia Papagiannaki
201 01ac12d5 Sofia Papagiannaki
    @property
202 0f4fa26d Sofia Papagiannaki
    def owners(self):
203 0f4fa26d Sofia Papagiannaki
        return self.owner.all()
204 5ce3ce4f Sofia Papagiannaki
205 032ade79 Sofia Papagiannaki
    @property
206 032ade79 Sofia Papagiannaki
    def owner_details(self):
207 032ade79 Sofia Papagiannaki
        return self.owner.select_related().all()
208 032ade79 Sofia Papagiannaki
209 0f4fa26d Sofia Papagiannaki
    @owners.setter
210 0f4fa26d Sofia Papagiannaki
    def owners(self, l):
211 0f4fa26d Sofia Papagiannaki
        self.owner = l
212 0f4fa26d Sofia Papagiannaki
        map(self.approve_member, l)
213 8e45d6fd Sofia Papagiannaki
214 5ce3ce4f Sofia Papagiannaki
215 0905ccd2 Sofia Papagiannaki
class AstakosUser(User):
216 890b0eaf Sofia Papagiannaki
    """
217 890b0eaf Sofia Papagiannaki
    Extends ``django.contrib.auth.models.User`` by defining additional fields.
218 890b0eaf Sofia Papagiannaki
    """
219 0905ccd2 Sofia Papagiannaki
    # Use UserManager to get the create_user method, etc.
220 0905ccd2 Sofia Papagiannaki
    objects = UserManager()
221 6c736ed7 Kostas Papadimitriou
222 5ed6816e Sofia Papagiannaki
    affiliation = models.CharField('Affiliation', max_length=255, blank=True)
223 5ed6816e Sofia Papagiannaki
    provider = models.CharField('Provider', max_length=255, blank=True)
224 6c736ed7 Kostas Papadimitriou
225 64cd4730 Antony Chazapis
    #for invitations
226 92defad4 Sofia Papagiannaki
    user_level = DEFAULT_USER_LEVEL
227 a196eb7e Sofia Papagiannaki
    level = models.IntegerField('Inviter level', default=user_level)
228 5ce3ce4f Sofia Papagiannaki
    invitations = models.IntegerField(
229 5ce3ce4f Sofia Papagiannaki
        'Invitations left', default=INVITATIONS_PER_LEVEL.get(user_level, 0))
230 6c736ed7 Kostas Papadimitriou
231 64cd4730 Antony Chazapis
    auth_token = models.CharField('Authentication Token', max_length=32,
232 0905ccd2 Sofia Papagiannaki
                                  null=True, blank=True)
233 0905ccd2 Sofia Papagiannaki
    auth_token_created = models.DateTimeField('Token creation date', null=True)
234 5ce3ce4f Sofia Papagiannaki
    auth_token_expires = models.DateTimeField(
235 5ce3ce4f Sofia Papagiannaki
        'Token expiration date', null=True)
236 6c736ed7 Kostas Papadimitriou
237 64cd4730 Antony Chazapis
    updated = models.DateTimeField('Update date')
238 890b0eaf Sofia Papagiannaki
    is_verified = models.BooleanField('Is verified?', default=False)
239 6c736ed7 Kostas Papadimitriou
240 15efc749 Sofia Papagiannaki
    # ex. screen_name for twitter, eppn for shibboleth
241 5ce3ce4f Sofia Papagiannaki
    third_party_identifier = models.CharField(
242 5ce3ce4f Sofia Papagiannaki
        'Third-party identifier', max_length=255, null=True, blank=True)
243 6c736ed7 Kostas Papadimitriou
244 ebd369d0 Sofia Papagiannaki
    email_verified = models.BooleanField('Email verified?', default=False)
245 6c736ed7 Kostas Papadimitriou
246 59f598f1 Sofia Papagiannaki
    has_credits = models.BooleanField('Has credits?', default=False)
247 5ce3ce4f Sofia Papagiannaki
    has_signed_terms = models.BooleanField(
248 5ce3ce4f Sofia Papagiannaki
        'Agree with the terms?', default=False)
249 5ce3ce4f Sofia Papagiannaki
    date_signed_terms = models.DateTimeField(
250 5ce3ce4f Sofia Papagiannaki
        'Signed terms date', null=True, blank=True)
251 5ce3ce4f Sofia Papagiannaki
252 5ce3ce4f Sofia Papagiannaki
    activation_sent = models.DateTimeField(
253 5ce3ce4f Sofia Papagiannaki
        'Activation sent data', null=True, blank=True)
254 5ce3ce4f Sofia Papagiannaki
255 5ce3ce4f Sofia Papagiannaki
    policy = models.ManyToManyField(
256 5ce3ce4f Sofia Papagiannaki
        Resource, null=True, through='AstakosUserQuota')
257 5ce3ce4f Sofia Papagiannaki
258 5ce3ce4f Sofia Papagiannaki
    astakos_groups = models.ManyToManyField(
259 5ce3ce4f Sofia Papagiannaki
        AstakosGroup, verbose_name=_('agroups'), blank=True,
260 29816137 Sofia Papagiannaki
        help_text=_("""In addition to the permissions manually assigned, this
261 29816137 Sofia Papagiannaki
                    user will also get all permissions granted to each group
262 29816137 Sofia Papagiannaki
                    he/she is in."""),
263 8e45d6fd Sofia Papagiannaki
        through='Membership')
264 5ce3ce4f Sofia Papagiannaki
265 18ffbee1 Sofia Papagiannaki
    __has_signed_terms = False
266 5ce3ce4f Sofia Papagiannaki
267 5ce3ce4f Sofia Papagiannaki
    owner = models.ManyToManyField(
268 5ce3ce4f Sofia Papagiannaki
        AstakosGroup, related_name='owner', null=True)
269 5ce3ce4f Sofia Papagiannaki
270 74b273d8 Sofia Papagiannaki
    class Meta:
271 74b273d8 Sofia Papagiannaki
        unique_together = ("provider", "third_party_identifier")
272 5ce3ce4f Sofia Papagiannaki
273 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
274 18ffbee1 Sofia Papagiannaki
        super(AstakosUser, self).__init__(*args, **kwargs)
275 18ffbee1 Sofia Papagiannaki
        self.__has_signed_terms = self.has_signed_terms
276 aa4109d4 Sofia Papagiannaki
        if not self.id:
277 18ffbee1 Sofia Papagiannaki
            self.is_active = False
278 5ce3ce4f Sofia Papagiannaki
279 0905ccd2 Sofia Papagiannaki
    @property
280 0905ccd2 Sofia Papagiannaki
    def realname(self):
281 5ce3ce4f Sofia Papagiannaki
        return '%s %s' % (self.first_name, self.last_name)
282 6c736ed7 Kostas Papadimitriou
283 0905ccd2 Sofia Papagiannaki
    @realname.setter
284 0905ccd2 Sofia Papagiannaki
    def realname(self, value):
285 0905ccd2 Sofia Papagiannaki
        parts = value.split(' ')
286 0905ccd2 Sofia Papagiannaki
        if len(parts) == 2:
287 0905ccd2 Sofia Papagiannaki
            self.first_name = parts[0]
288 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[1]
289 0905ccd2 Sofia Papagiannaki
        else:
290 0905ccd2 Sofia Papagiannaki
            self.last_name = parts[0]
291 6c736ed7 Kostas Papadimitriou
292 64cd4730 Antony Chazapis
    @property
293 64cd4730 Antony Chazapis
    def invitation(self):
294 64cd4730 Antony Chazapis
        try:
295 9fb8e808 Sofia Papagiannaki
            return Invitation.objects.get(username=self.email)
296 64cd4730 Antony Chazapis
        except Invitation.DoesNotExist:
297 64cd4730 Antony Chazapis
            return None
298 5ce3ce4f Sofia Papagiannaki
299 ffb1e7a8 Sofia Papagiannaki
    @property
300 ffb1e7a8 Sofia Papagiannaki
    def quota(self):
301 ffb1e7a8 Sofia Papagiannaki
        d = defaultdict(int)
302 dfdc64d2 Sofia Papagiannaki
        for q in self.astakosuserquota_set.select_related().all():
303 9eafaa32 Sofia Papagiannaki
            d[q.resource] += q.uplimit
304 dfdc64d2 Sofia Papagiannaki
        for m in self.membership_set.select_related().all():
305 fc1e2f02 Sofia Papagiannaki
            if not m.is_approved:
306 fc1e2f02 Sofia Papagiannaki
                continue
307 fc1e2f02 Sofia Papagiannaki
            g = m.group
308 ffb1e7a8 Sofia Papagiannaki
            if not g.is_enabled:
309 ffb1e7a8 Sofia Papagiannaki
                continue
310 670de92a Sofia Papagiannaki
            for r, uplimit in g.quota.iteritems():
311 670de92a Sofia Papagiannaki
                d[r] += uplimit
312 9eafaa32 Sofia Papagiannaki
        
313 ffb1e7a8 Sofia Papagiannaki
        # TODO set default for remaining
314 ffb1e7a8 Sofia Papagiannaki
        return d
315 5ce3ce4f Sofia Papagiannaki
316 64cd4730 Antony Chazapis
    def save(self, update_timestamps=True, **kwargs):
317 64cd4730 Antony Chazapis
        if update_timestamps:
318 64cd4730 Antony Chazapis
            if not self.id:
319 0905ccd2 Sofia Papagiannaki
                self.date_joined = datetime.now()
320 64cd4730 Antony Chazapis
            self.updated = datetime.now()
321 5ce3ce4f Sofia Papagiannaki
322 18ffbee1 Sofia Papagiannaki
        # update date_signed_terms if necessary
323 18ffbee1 Sofia Papagiannaki
        if self.__has_signed_terms != self.has_signed_terms:
324 18ffbee1 Sofia Papagiannaki
            self.date_signed_terms = datetime.now()
325 5ce3ce4f Sofia Papagiannaki
326 9c01d9d1 Sofia Papagiannaki
        if not self.id:
327 9c01d9d1 Sofia Papagiannaki
            # set username
328 9c01d9d1 Sofia Papagiannaki
            while not self.username:
329 5ce3ce4f Sofia Papagiannaki
                username = uuid.uuid4().hex[:30]
330 9c01d9d1 Sofia Papagiannaki
                try:
331 5ce3ce4f Sofia Papagiannaki
                    AstakosUser.objects.get(username=username)
332 aab4d540 Sofia Papagiannaki
                except AstakosUser.DoesNotExist:
333 9c01d9d1 Sofia Papagiannaki
                    self.username = username
334 9c01d9d1 Sofia Papagiannaki
            if not self.provider:
335 9c01d9d1 Sofia Papagiannaki
                self.provider = 'local'
336 29816137 Sofia Papagiannaki
            self.email = self.email.lower()
337 591d0505 Sofia Papagiannaki
        self.validate_unique_email_isactive()
338 751d24cf Sofia Papagiannaki
        if self.is_active and self.activation_sent:
339 751d24cf Sofia Papagiannaki
            # reset the activation sent
340 751d24cf Sofia Papagiannaki
            self.activation_sent = None
341 5ce3ce4f Sofia Papagiannaki
342 0905ccd2 Sofia Papagiannaki
        super(AstakosUser, self).save(**kwargs)
343 5ce3ce4f Sofia Papagiannaki
344 64cd4730 Antony Chazapis
    def renew_token(self):
345 64cd4730 Antony Chazapis
        md5 = hashlib.md5()
346 0905ccd2 Sofia Papagiannaki
        md5.update(self.username)
347 64cd4730 Antony Chazapis
        md5.update(self.realname.encode('ascii', 'ignore'))
348 64cd4730 Antony Chazapis
        md5.update(asctime())
349 6c736ed7 Kostas Papadimitriou
350 64cd4730 Antony Chazapis
        self.auth_token = b64encode(md5.digest())
351 64cd4730 Antony Chazapis
        self.auth_token_created = datetime.now()
352 64cd4730 Antony Chazapis
        self.auth_token_expires = self.auth_token_created + \
353 5ce3ce4f Sofia Papagiannaki
            timedelta(hours=AUTH_TOKEN_DURATION)
354 111f3da6 Sofia Papagiannaki
        msg = 'Token renewed for %s' % self.email
355 aab4d540 Sofia Papagiannaki
        logger.log(LOGGING_LEVEL, msg)
356 6c736ed7 Kostas Papadimitriou
357 64cd4730 Antony Chazapis
    def __unicode__(self):
358 3abf6c78 Sofia Papagiannaki
        return '%s (%s)' % (self.realname, self.email)
359 5ce3ce4f Sofia Papagiannaki
360 0a569195 Sofia Papagiannaki
    def conflicting_email(self):
361 5ce3ce4f Sofia Papagiannaki
        q = AstakosUser.objects.exclude(username=self.username)
362 5ce3ce4f Sofia Papagiannaki
        q = q.filter(email=self.email)
363 0a569195 Sofia Papagiannaki
        if q.count() != 0:
364 0a569195 Sofia Papagiannaki
            return True
365 0a569195 Sofia Papagiannaki
        return False
366 5ce3ce4f Sofia Papagiannaki
367 591d0505 Sofia Papagiannaki
    def validate_unique_email_isactive(self):
368 0a569195 Sofia Papagiannaki
        """
369 0a569195 Sofia Papagiannaki
        Implements a unique_together constraint for email and is_active fields.
370 0a569195 Sofia Papagiannaki
        """
371 5ce3ce4f Sofia Papagiannaki
        q = AstakosUser.objects.exclude(username=self.username)
372 5ce3ce4f Sofia Papagiannaki
        q = q.filter(email=self.email)
373 5ce3ce4f Sofia Papagiannaki
        q = q.filter(is_active=self.is_active)
374 0a569195 Sofia Papagiannaki
        if q.count() != 0:
375 5ce3ce4f Sofia Papagiannaki
            raise ValidationError({'__all__': [_('Another account with the same email & is_active combination found.')]})
376 5ce3ce4f Sofia Papagiannaki
377 fcf90160 Sofia Papagiannaki
    @property
378 09e7393c Sofia Papagiannaki
    def signed_terms(self):
379 09e7393c Sofia Papagiannaki
        term = get_latest_terms()
380 09e7393c Sofia Papagiannaki
        if not term:
381 09e7393c Sofia Papagiannaki
            return True
382 09e7393c Sofia Papagiannaki
        if not self.has_signed_terms:
383 09e7393c Sofia Papagiannaki
            return False
384 09e7393c Sofia Papagiannaki
        if not self.date_signed_terms:
385 09e7393c Sofia Papagiannaki
            return False
386 09e7393c Sofia Papagiannaki
        if self.date_signed_terms < term.date:
387 09e7393c Sofia Papagiannaki
            self.has_signed_terms = False
388 f0f92965 Sofia Papagiannaki
            self.date_signed_terms = None
389 09e7393c Sofia Papagiannaki
            self.save()
390 09e7393c Sofia Papagiannaki
            return False
391 09e7393c Sofia Papagiannaki
        return True
392 8e45d6fd Sofia Papagiannaki
393 5ce3ce4f Sofia Papagiannaki
394 8e45d6fd Sofia Papagiannaki
class Membership(models.Model):
395 8e45d6fd Sofia Papagiannaki
    person = models.ForeignKey(AstakosUser)
396 8e45d6fd Sofia Papagiannaki
    group = models.ForeignKey(AstakosGroup)
397 01ac12d5 Sofia Papagiannaki
    date_requested = models.DateField(default=datetime.now(), blank=True)
398 01ac12d5 Sofia Papagiannaki
    date_joined = models.DateField(null=True, db_index=True, blank=True)
399 5ce3ce4f Sofia Papagiannaki
400 8e45d6fd Sofia Papagiannaki
    class Meta:
401 8e45d6fd Sofia Papagiannaki
        unique_together = ("person", "group")
402 5ce3ce4f Sofia Papagiannaki
403 ffb1e7a8 Sofia Papagiannaki
    def save(self, *args, **kwargs):
404 28252c7f Sofia Papagiannaki
        if not self.id:
405 28252c7f Sofia Papagiannaki
            if not self.group.moderation_enabled:
406 28252c7f Sofia Papagiannaki
                self.date_joined = datetime.now()
407 ffb1e7a8 Sofia Papagiannaki
        super(Membership, self).save(*args, **kwargs)
408 5ce3ce4f Sofia Papagiannaki
409 8e45d6fd Sofia Papagiannaki
    @property
410 8e45d6fd Sofia Papagiannaki
    def is_approved(self):
411 8e45d6fd Sofia Papagiannaki
        if self.date_joined:
412 8e45d6fd Sofia Papagiannaki
            return True
413 8e45d6fd Sofia Papagiannaki
        return False
414 5ce3ce4f Sofia Papagiannaki
415 01ac12d5 Sofia Papagiannaki
    def approve(self):
416 01ac12d5 Sofia Papagiannaki
        self.date_joined = datetime.now()
417 01ac12d5 Sofia Papagiannaki
        self.save()
418 fc1e2f02 Sofia Papagiannaki
        quota_disturbed.send(sender=self, users=(self.person,))
419 5ce3ce4f Sofia Papagiannaki
420 01ac12d5 Sofia Papagiannaki
    def disapprove(self):
421 01ac12d5 Sofia Papagiannaki
        self.delete()
422 fc1e2f02 Sofia Papagiannaki
        quota_disturbed.send(sender=self, users=(self.person,))
423 8e45d6fd Sofia Papagiannaki
424 5ce3ce4f Sofia Papagiannaki
425 8e45d6fd Sofia Papagiannaki
class AstakosGroupQuota(models.Model):
426 7507ea03 root
    limit = models.PositiveIntegerField('Limit', null=True)    # obsolete field
427 670de92a Sofia Papagiannaki
    uplimit = models.BigIntegerField('Up limit', null=True)
428 8e45d6fd Sofia Papagiannaki
    resource = models.ForeignKey(Resource)
429 8e45d6fd Sofia Papagiannaki
    group = models.ForeignKey(AstakosGroup, blank=True)
430 5ce3ce4f Sofia Papagiannaki
431 8e45d6fd Sofia Papagiannaki
    class Meta:
432 8e45d6fd Sofia Papagiannaki
        unique_together = ("resource", "group")
433 8e45d6fd Sofia Papagiannaki
434 5ce3ce4f Sofia Papagiannaki
435 8e45d6fd Sofia Papagiannaki
class AstakosUserQuota(models.Model):
436 7507ea03 root
    limit = models.PositiveIntegerField('Limit', null=True)    # obsolete field
437 670de92a Sofia Papagiannaki
    uplimit = models.BigIntegerField('Up limit', null=True)
438 8e45d6fd Sofia Papagiannaki
    resource = models.ForeignKey(Resource)
439 8e45d6fd Sofia Papagiannaki
    user = models.ForeignKey(AstakosUser)
440 5ce3ce4f Sofia Papagiannaki
441 8e45d6fd Sofia Papagiannaki
    class Meta:
442 8e45d6fd Sofia Papagiannaki
        unique_together = ("resource", "user")
443 09e7393c Sofia Papagiannaki
444 5ce3ce4f Sofia Papagiannaki
445 270dd48d Sofia Papagiannaki
class ApprovalTerms(models.Model):
446 270dd48d Sofia Papagiannaki
    """
447 270dd48d Sofia Papagiannaki
    Model for approval terms
448 270dd48d Sofia Papagiannaki
    """
449 6c736ed7 Kostas Papadimitriou
450 5ce3ce4f Sofia Papagiannaki
    date = models.DateTimeField(
451 5ce3ce4f Sofia Papagiannaki
        'Issue date', db_index=True, default=datetime.now())
452 270dd48d Sofia Papagiannaki
    location = models.CharField('Terms location', max_length=255)
453 270dd48d Sofia Papagiannaki
454 5ce3ce4f Sofia Papagiannaki
455 64cd4730 Antony Chazapis
class Invitation(models.Model):
456 890b0eaf Sofia Papagiannaki
    """
457 890b0eaf Sofia Papagiannaki
    Model for registring invitations
458 890b0eaf Sofia Papagiannaki
    """
459 0905ccd2 Sofia Papagiannaki
    inviter = models.ForeignKey(AstakosUser, related_name='invitations_sent',
460 64cd4730 Antony Chazapis
                                null=True)
461 64cd4730 Antony Chazapis
    realname = models.CharField('Real name', max_length=255)
462 ebd369d0 Sofia Papagiannaki
    username = models.CharField('Unique ID', max_length=255, unique=True)
463 64cd4730 Antony Chazapis
    code = models.BigIntegerField('Invitation code', db_index=True)
464 64cd4730 Antony Chazapis
    is_consumed = models.BooleanField('Consumed?', default=False)
465 64cd4730 Antony Chazapis
    created = models.DateTimeField('Creation date', auto_now_add=True)
466 64cd4730 Antony Chazapis
    consumed = models.DateTimeField('Consumption date', null=True, blank=True)
467 5ce3ce4f Sofia Papagiannaki
468 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
469 18ffbee1 Sofia Papagiannaki
        super(Invitation, self).__init__(*args, **kwargs)
470 8f5a3a06 Sofia Papagiannaki
        if not self.id:
471 8f5a3a06 Sofia Papagiannaki
            self.code = _generate_invitation_code()
472 5ce3ce4f Sofia Papagiannaki
473 64cd4730 Antony Chazapis
    def consume(self):
474 64cd4730 Antony Chazapis
        self.is_consumed = True
475 64cd4730 Antony Chazapis
        self.consumed = datetime.now()
476 64cd4730 Antony Chazapis
        self.save()
477 6c736ed7 Kostas Papadimitriou
478 64cd4730 Antony Chazapis
    def __unicode__(self):
479 0905ccd2 Sofia Papagiannaki
        return '%s -> %s [%d]' % (self.inviter, self.username, self.code)
480 9c01d9d1 Sofia Papagiannaki
481 5ce3ce4f Sofia Papagiannaki
482 49790d9d Sofia Papagiannaki
class EmailChangeManager(models.Manager):
483 49790d9d Sofia Papagiannaki
    @transaction.commit_on_success
484 49790d9d Sofia Papagiannaki
    def change_email(self, activation_key):
485 49790d9d Sofia Papagiannaki
        """
486 49790d9d Sofia Papagiannaki
        Validate an activation key and change the corresponding
487 49790d9d Sofia Papagiannaki
        ``User`` if valid.
488 49790d9d Sofia Papagiannaki

489 49790d9d Sofia Papagiannaki
        If the key is valid and has not expired, return the ``User``
490 49790d9d Sofia Papagiannaki
        after activating.
491 49790d9d Sofia Papagiannaki

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

494 49790d9d Sofia Papagiannaki
        If the key is valid but the ``User`` is already active,
495 49790d9d Sofia Papagiannaki
        return ``None``.
496 49790d9d Sofia Papagiannaki

497 49790d9d Sofia Papagiannaki
        After successful email change the activation record is deleted.
498 49790d9d Sofia Papagiannaki

499 49790d9d Sofia Papagiannaki
        Throws ValueError if there is already
500 49790d9d Sofia Papagiannaki
        """
501 49790d9d Sofia Papagiannaki
        try:
502 5ce3ce4f Sofia Papagiannaki
            email_change = self.model.objects.get(
503 5ce3ce4f Sofia Papagiannaki
                activation_key=activation_key)
504 49790d9d Sofia Papagiannaki
            if email_change.activation_key_expired():
505 49790d9d Sofia Papagiannaki
                email_change.delete()
506 49790d9d Sofia Papagiannaki
                raise EmailChange.DoesNotExist
507 49790d9d Sofia Papagiannaki
            # is there an active user with this address?
508 49790d9d Sofia Papagiannaki
            try:
509 49790d9d Sofia Papagiannaki
                AstakosUser.objects.get(email=email_change.new_email_address)
510 49790d9d Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
511 49790d9d Sofia Papagiannaki
                pass
512 49790d9d Sofia Papagiannaki
            else:
513 49790d9d Sofia Papagiannaki
                raise ValueError(_('The new email address is reserved.'))
514 49790d9d Sofia Papagiannaki
            # update user
515 49790d9d Sofia Papagiannaki
            user = AstakosUser.objects.get(pk=email_change.user_id)
516 49790d9d Sofia Papagiannaki
            user.email = email_change.new_email_address
517 49790d9d Sofia Papagiannaki
            user.save()
518 49790d9d Sofia Papagiannaki
            email_change.delete()
519 49790d9d Sofia Papagiannaki
            return user
520 49790d9d Sofia Papagiannaki
        except EmailChange.DoesNotExist:
521 49790d9d Sofia Papagiannaki
            raise ValueError(_('Invalid activation key'))
522 49790d9d Sofia Papagiannaki
523 5ce3ce4f Sofia Papagiannaki
524 49790d9d Sofia Papagiannaki
class EmailChange(models.Model):
525 29816137 Sofia Papagiannaki
    new_email_address = models.EmailField(_(u'new e-mail address'),
526 29816137 Sofia Papagiannaki
        help_text=_(u'Your old email address will be used until you verify your new one.'))
527 5ce3ce4f Sofia Papagiannaki
    user = models.ForeignKey(
528 5ce3ce4f Sofia Papagiannaki
        AstakosUser, unique=True, related_name='emailchange_user')
529 49790d9d Sofia Papagiannaki
    requested_at = models.DateTimeField(default=datetime.now())
530 5ce3ce4f Sofia Papagiannaki
    activation_key = models.CharField(
531 5ce3ce4f Sofia Papagiannaki
        max_length=40, unique=True, db_index=True)
532 49790d9d Sofia Papagiannaki
533 49790d9d Sofia Papagiannaki
    objects = EmailChangeManager()
534 49790d9d Sofia Papagiannaki
535 49790d9d Sofia Papagiannaki
    def activation_key_expired(self):
536 49790d9d Sofia Papagiannaki
        expiration_date = timedelta(days=EMAILCHANGE_ACTIVATION_DAYS)
537 ff9290ec Sofia Papagiannaki
        return self.requested_at + expiration_date < datetime.now()
538 ff9290ec Sofia Papagiannaki
539 5ce3ce4f Sofia Papagiannaki
540 ca828a10 Sofia Papagiannaki
class AdditionalMail(models.Model):
541 ca828a10 Sofia Papagiannaki
    """
542 ca828a10 Sofia Papagiannaki
    Model for registring invitations
543 ca828a10 Sofia Papagiannaki
    """
544 ca828a10 Sofia Papagiannaki
    owner = models.ForeignKey(AstakosUser)
545 1eec103a Sofia Papagiannaki
    email = models.EmailField()
546 ca828a10 Sofia Papagiannaki
547 5ce3ce4f Sofia Papagiannaki
548 fc1e2f02 Sofia Papagiannaki
def _generate_invitation_code():
549 fc1e2f02 Sofia Papagiannaki
    while True:
550 5ce3ce4f Sofia Papagiannaki
        code = randint(1, 2L ** 63 - 1)
551 fc1e2f02 Sofia Papagiannaki
        try:
552 fc1e2f02 Sofia Papagiannaki
            Invitation.objects.get(code=code)
553 fc1e2f02 Sofia Papagiannaki
            # An invitation with this code already exists, try again
554 fc1e2f02 Sofia Papagiannaki
        except Invitation.DoesNotExist:
555 fc1e2f02 Sofia Papagiannaki
            return code
556 fc1e2f02 Sofia Papagiannaki
557 5ce3ce4f Sofia Papagiannaki
558 fc1e2f02 Sofia Papagiannaki
def get_latest_terms():
559 fc1e2f02 Sofia Papagiannaki
    try:
560 fc1e2f02 Sofia Papagiannaki
        term = ApprovalTerms.objects.order_by('-id')[0]
561 fc1e2f02 Sofia Papagiannaki
        return term
562 fc1e2f02 Sofia Papagiannaki
    except IndexError:
563 fc1e2f02 Sofia Papagiannaki
        pass
564 fc1e2f02 Sofia Papagiannaki
    return None
565 fc1e2f02 Sofia Papagiannaki
566 5ce3ce4f Sofia Papagiannaki
567 ff9290ec Sofia Papagiannaki
def create_astakos_user(u):
568 ff9290ec Sofia Papagiannaki
    try:
569 ff9290ec Sofia Papagiannaki
        AstakosUser.objects.get(user_ptr=u.pk)
570 ff9290ec Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
571 ff9290ec Sofia Papagiannaki
        extended_user = AstakosUser(user_ptr_id=u.pk)
572 ff9290ec Sofia Papagiannaki
        extended_user.__dict__.update(u.__dict__)
573 ff9290ec Sofia Papagiannaki
        extended_user.renew_token()
574 ff9290ec Sofia Papagiannaki
        extended_user.save()
575 fc1e2f02 Sofia Papagiannaki
    except BaseException, e:
576 fc1e2f02 Sofia Papagiannaki
        logger.exception(e)
577 ff9290ec Sofia Papagiannaki
        pass
578 ff9290ec Sofia Papagiannaki
579 5ce3ce4f Sofia Papagiannaki
580 fc1e2f02 Sofia Papagiannaki
def fix_superusers(sender, **kwargs):
581 fc1e2f02 Sofia Papagiannaki
    # Associate superusers with AstakosUser
582 ff9290ec Sofia Papagiannaki
    admins = User.objects.filter(is_superuser=True)
583 ff9290ec Sofia Papagiannaki
    for u in admins:
584 ff9290ec Sofia Papagiannaki
        create_astakos_user(u)
585 ff9290ec Sofia Papagiannaki
586 5ce3ce4f Sofia Papagiannaki
587 fc1e2f02 Sofia Papagiannaki
def user_post_save(sender, instance, created, **kwargs):
588 aa4109d4 Sofia Papagiannaki
    if not created:
589 aa4109d4 Sofia Papagiannaki
        return
590 fc1e2f02 Sofia Papagiannaki
    create_astakos_user(instance)
591 fc1e2f02 Sofia Papagiannaki
592 5ce3ce4f Sofia Papagiannaki
593 fc1e2f02 Sofia Papagiannaki
def set_default_group(user):
594 aa4109d4 Sofia Papagiannaki
    try:
595 5ce3ce4f Sofia Papagiannaki
        default = AstakosGroup.objects.get(name='default')
596 5ce3ce4f Sofia Papagiannaki
        Membership(
597 5ce3ce4f Sofia Papagiannaki
            group=default, person=user, date_joined=datetime.now()).save()
598 aa4109d4 Sofia Papagiannaki
    except AstakosGroup.DoesNotExist, e:
599 aa4109d4 Sofia Papagiannaki
        logger.exception(e)
600 aa4109d4 Sofia Papagiannaki
601 5ce3ce4f Sofia Papagiannaki
602 fc1e2f02 Sofia Papagiannaki
def astakosuser_pre_save(sender, instance, **kwargs):
603 fc1e2f02 Sofia Papagiannaki
    instance.aquarium_report = False
604 fc1e2f02 Sofia Papagiannaki
    instance.new = False
605 fc1e2f02 Sofia Papagiannaki
    try:
606 5ce3ce4f Sofia Papagiannaki
        db_instance = AstakosUser.objects.get(id=instance.id)
607 fc1e2f02 Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
608 fc1e2f02 Sofia Papagiannaki
        # create event
609 fc1e2f02 Sofia Papagiannaki
        instance.aquarium_report = True
610 fc1e2f02 Sofia Papagiannaki
        instance.new = True
611 fc1e2f02 Sofia Papagiannaki
    else:
612 fc1e2f02 Sofia Papagiannaki
        get = AstakosUser.__getattribute__
613 fc1e2f02 Sofia Papagiannaki
        l = filter(lambda f: get(db_instance, f) != get(instance, f),
614 5ce3ce4f Sofia Papagiannaki
                   BILLING_FIELDS
615 5ce3ce4f Sofia Papagiannaki
                   )
616 fc1e2f02 Sofia Papagiannaki
        instance.aquarium_report = True if l else False
617 fc1e2f02 Sofia Papagiannaki
618 5ce3ce4f Sofia Papagiannaki
619 fc1e2f02 Sofia Papagiannaki
def astakosuser_post_save(sender, instance, created, **kwargs):
620 fc1e2f02 Sofia Papagiannaki
    if instance.aquarium_report:
621 fc1e2f02 Sofia Papagiannaki
        report_user_event(instance, create=instance.new)
622 fc1e2f02 Sofia Papagiannaki
    if not created:
623 fc1e2f02 Sofia Papagiannaki
        return
624 fc1e2f02 Sofia Papagiannaki
    set_default_group(instance)
625 fc1e2f02 Sofia Papagiannaki
    # TODO handle socket.error & IOError
626 fc1e2f02 Sofia Papagiannaki
    register_users((instance,))
627 fc1e2f02 Sofia Papagiannaki
628 5ce3ce4f Sofia Papagiannaki
629 bd4f356c Sofia Papagiannaki
def resource_post_save(sender, instance, created, **kwargs):
630 bd4f356c Sofia Papagiannaki
    if not created:
631 bd4f356c Sofia Papagiannaki
        return
632 bd4f356c Sofia Papagiannaki
    register_resources((instance,))
633 bd4f356c Sofia Papagiannaki
634 bd4f356c Sofia Papagiannaki
635 fc1e2f02 Sofia Papagiannaki
def send_quota_disturbed(sender, instance, **kwargs):
636 fc1e2f02 Sofia Papagiannaki
    users = []
637 fc1e2f02 Sofia Papagiannaki
    extend = users.extend
638 fc1e2f02 Sofia Papagiannaki
    if sender == Membership:
639 fc1e2f02 Sofia Papagiannaki
        if not instance.group.is_enabled:
640 fc1e2f02 Sofia Papagiannaki
            return
641 fc1e2f02 Sofia Papagiannaki
        extend([instance.person])
642 fc1e2f02 Sofia Papagiannaki
    elif sender == AstakosUserQuota:
643 fc1e2f02 Sofia Papagiannaki
        extend([instance.user])
644 fc1e2f02 Sofia Papagiannaki
    elif sender == AstakosGroupQuota:
645 fc1e2f02 Sofia Papagiannaki
        if not instance.group.is_enabled:
646 fc1e2f02 Sofia Papagiannaki
            return
647 fc1e2f02 Sofia Papagiannaki
        extend(instance.group.astakosuser_set.all())
648 fc1e2f02 Sofia Papagiannaki
    elif sender == AstakosGroup:
649 fc1e2f02 Sofia Papagiannaki
        if not instance.is_enabled:
650 fc1e2f02 Sofia Papagiannaki
            return
651 fc1e2f02 Sofia Papagiannaki
    quota_disturbed.send(sender=sender, users=users)
652 fc1e2f02 Sofia Papagiannaki
653 5ce3ce4f Sofia Papagiannaki
654 fc1e2f02 Sofia Papagiannaki
def on_quota_disturbed(sender, users, **kwargs):
655 fc1e2f02 Sofia Papagiannaki
    print '>>>', locals()
656 fc1e2f02 Sofia Papagiannaki
    if not users:
657 fc1e2f02 Sofia Papagiannaki
        return
658 fc1e2f02 Sofia Papagiannaki
    send_quota(users)
659 fc1e2f02 Sofia Papagiannaki
660 fc1e2f02 Sofia Papagiannaki
post_syncdb.connect(fix_superusers)
661 fc1e2f02 Sofia Papagiannaki
post_save.connect(user_post_save, sender=User)
662 fc1e2f02 Sofia Papagiannaki
pre_save.connect(astakosuser_pre_save, sender=AstakosUser)
663 fc1e2f02 Sofia Papagiannaki
post_save.connect(astakosuser_post_save, sender=AstakosUser)
664 bd4f356c Sofia Papagiannaki
post_save.connect(resource_post_save, sender=Resource)
665 fc1e2f02 Sofia Papagiannaki
666 fc1e2f02 Sofia Papagiannaki
quota_disturbed = Signal(providing_args=["users"])
667 fc1e2f02 Sofia Papagiannaki
quota_disturbed.connect(on_quota_disturbed)
668 fc1e2f02 Sofia Papagiannaki
669 fc1e2f02 Sofia Papagiannaki
post_delete.connect(send_quota_disturbed, sender=AstakosGroup)
670 fc1e2f02 Sofia Papagiannaki
post_delete.connect(send_quota_disturbed, sender=Membership)
671 fc1e2f02 Sofia Papagiannaki
post_save.connect(send_quota_disturbed, sender=AstakosUserQuota)
672 fc1e2f02 Sofia Papagiannaki
post_delete.connect(send_quota_disturbed, sender=AstakosUserQuota)
673 fc1e2f02 Sofia Papagiannaki
post_save.connect(send_quota_disturbed, sender=AstakosGroupQuota)
674 5ce3ce4f Sofia Papagiannaki
post_delete.connect(send_quota_disturbed, sender=AstakosGroupQuota)