Revision fcc1e93f snf-astakos-app/astakos/im/models.py

b/snf-astakos-app/astakos/im/models.py
165 165
    def __str__(self):
166 166
        return '%s%s%s' % (self.service, RESOURCE_SEPARATOR, self.name)
167 167

  
168

  
169
class GroupKind(models.Model):
170
    name = models.CharField(_('Name'), max_length=255, unique=True, db_index=True)
171

  
172
    def __str__(self):
173
        return self.name
174

  
175

  
176
class AstakosGroup(Group):
177
    kind = models.ForeignKey(GroupKind)
178
    homepage = models.URLField(
179
        _('Homepage Url'), max_length=255, null=True, blank=True)
180
    desc = models.TextField(_('Description'), null=True)
181
    policy = models.ManyToManyField(
182
        Resource,
183
        null=True,
184
        blank=True,
185
        through='AstakosGroupQuota'
186
    )
187
    creation_date = models.DateTimeField(
188
        _('Creation date'),
189
        default=datetime.now()
190
    )
191
    issue_date = models.DateTimeField(
192
        _('Start date'),
193
        null=True
194
    )
195
    expiration_date = models.DateTimeField(
196
        _('Expiration date'),
197
        null=True
198
    )
199
    moderation_enabled = models.BooleanField(
200
        _('Moderated membership?'),
201
        default=True
202
    )
203
    approval_date = models.DateTimeField(
204
        _('Activation date'),
205
        null=True,
206
        blank=True
207
    )
208
    estimated_participants = models.PositiveIntegerField(
209
        _('Estimated #members'),
210
        null=True,
211
        blank=True,
212
    )
213
    max_participants = models.PositiveIntegerField(
214
        _('Maximum numder of participants'),
215
        null=True,
216
        blank=True
217
    )
218

  
219
    @property
220
    def is_disabled(self):
221
        if not self.approval_date:
222
            return True
223
        return False
224

  
225
    @property
226
    def is_enabled(self):
227
        if self.is_disabled:
228
            return False
229
        if not self.issue_date:
230
            return False
231
        if not self.expiration_date:
232
            return True
233
        now = datetime.now()
234
        if self.issue_date > now:
235
            return False
236
        if now >= self.expiration_date:
237
            return False
238
        return True
239

  
240
    def enable(self):
241
        if self.is_enabled:
242
            return
243
        self.approval_date = datetime.now()
244
        self.save()
245
        quota_disturbed.send(sender=self, users=self.approved_members)
246
        #propagate_groupmembers_quota.apply_async(
247
        #    args=[self], eta=self.issue_date)
248
        #propagate_groupmembers_quota.apply_async(
249
        #    args=[self], eta=self.expiration_date)
250

  
251
    def disable(self):
252
        if self.is_disabled:
253
            return
254
        self.approval_date = None
255
        self.save()
256
        quota_disturbed.send(sender=self, users=self.approved_members)
257

  
258
    def approve_member(self, person):
259
        m, created = self.membership_set.get_or_create(person=person)
260
        m.approve()
261

  
262
    @property
263
    def members(self):
264
        q = self.membership_set.select_related().all()
265
        return [m.person for m in q]
266

  
267
    @property
268
    def approved_members(self):
269
        q = self.membership_set.select_related().all()
270
        return [m.person for m in q if m.is_approved]
271

  
272
    @property
273
    def quota(self):
274
        d = defaultdict(int)
275
        for q in self.astakosgroupquota_set.select_related().all():
276
            d[q.resource] += q.uplimit or inf
277
        return d
278

  
279
    def add_policy(self, service, resource, uplimit, update=True):
280
        """Raises ObjectDoesNotExist, IntegrityError"""
281
        resource = Resource.objects.get(service__name=service, name=resource)
282
        if update:
283
            AstakosGroupQuota.objects.update_or_create(
284
                group=self,
285
                resource=resource,
286
                defaults={'uplimit': uplimit}
287
            )
288
        else:
289
            q = self.astakosgroupquota_set
290
            q.create(resource=resource, uplimit=uplimit)
291

  
292
    @property
293
    def policies(self):
294
        return self.astakosgroupquota_set.select_related().all()
295

  
296
    @policies.setter
297
    def policies(self, policies):
298
        for p in policies:
299
            service = p.get('service', None)
300
            resource = p.get('resource', None)
301
            uplimit = p.get('uplimit', 0)
302
            update = p.get('update', True)
303
            self.add_policy(service, resource, uplimit, update)
304

  
305
    @property
306
    def owners(self):
307
        return self.owner.all()
308

  
309
    @property
310
    def owner_details(self):
311
        return self.owner.select_related().all()
312

  
313
    @owners.setter
314
    def owners(self, l):
315
        self.owner = l
316
        map(self.approve_member, l)
317

  
318 168
_default_quota = {}
319 169
def get_default_quota():
320 170
    global _default_quota
......
403 253

  
404 254
    uuid = models.CharField(max_length=255, null=True, blank=False, unique=True)
405 255

  
406
    astakos_groups = models.ManyToManyField(
407
        AstakosGroup, verbose_name=_('agroups'), blank=True,
408
        help_text=_(astakos_messages.ASTAKOSUSER_GROUPS_HELP),
409
        through='Membership')
410

  
411 256
    __has_signed_terms = False
412 257
    disturbed_quota = models.BooleanField(_('Needs quotaholder syncing'),
413 258
                                           default=False, db_index=True)
414 259

  
415 260
    objects = AstakosUserManager()
416 261

  
417

  
418
    owner = models.ManyToManyField(
419
        AstakosGroup, related_name='owner', null=True)
420

  
421 262
    def __init__(self, *args, **kwargs):
422 263
        super(AstakosUser, self).__init__(*args, **kwargs)
423 264
        self.__has_signed_terms = self.has_signed_terms
......
522 363
    def extended_groups(self):
523 364
        return self.membership_set.select_related().all()
524 365

  
525
    @extended_groups.setter
526
    def extended_groups(self, groups):
527
        #TODO exceptions
528
        for name in (groups or ()):
529
            group = AstakosGroup.objects.get(name=name)
530
            self.membership_set.create(group=group)
531

  
532 366
    def save(self, update_timestamps=True, **kwargs):
533 367
        if update_timestamps:
534 368
            if not self.id:
......
891 725
        return super(AstakosUserAuthProvider, self).save(*args, **kwargs)
892 726

  
893 727

  
894
class Membership(models.Model):
895
    person = models.ForeignKey(AstakosUser)
896
    group = models.ForeignKey(AstakosGroup)
897
    date_requested = models.DateField(default=datetime.now(), blank=True)
898
    date_joined = models.DateField(null=True, db_index=True, blank=True)
899

  
900
    class Meta:
901
        unique_together = ("person", "group")
902

  
903
    def save(self, *args, **kwargs):
904
        if not self.id:
905
            if not self.group.moderation_enabled:
906
                self.date_joined = datetime.now()
907
        super(Membership, self).save(*args, **kwargs)
908

  
909
    @property
910
    def is_approved(self):
911
        if self.date_joined:
912
            return True
913
        return False
914

  
915
    def approve(self):
916
        if self.is_approved:
917
            return
918
        if self.group.max_participants:
919
            assert len(self.group.approved_members) + 1 <= self.group.max_participants, \
920
            'Maximum participant number has been reached.'
921
        self.date_joined = datetime.now()
922
        self.save()
923
        quota_disturbed.send(sender=self, users=(self.person,))
924

  
925
    def disapprove(self):
926
        approved = self.is_approved()
927
        self.delete()
928
        if approved:
929
            quota_disturbed.send(sender=self, users=(self.person,))
930

  
931 728
class ExtendedManager(models.Manager):
932 729
    def _update_or_create(self, **kwargs):
933 730
        assert kwargs, \
......
957 754

  
958 755
    update_or_create = _update_or_create
959 756

  
960
class AstakosGroupQuota(models.Model):
961
    objects = ExtendedManager()
962
    limit = models.PositiveIntegerField(_('Limit'), null=True)    # obsolete field
963
    uplimit = models.BigIntegerField(_('Up limit'), null=True)
964
    resource = models.ForeignKey(Resource)
965
    group = models.ForeignKey(AstakosGroup, blank=True)
966

  
967
    class Meta:
968
        unique_together = ("resource", "group")
969 757

  
970 758
class AstakosUserQuota(models.Model):
971 759
    objects = ExtendedManager()
......
1171 959
    session_key = models.CharField(_('session key'), max_length=40)
1172 960
    user = models.ForeignKey(AstakosUser, related_name='sessions', null=True)
1173 961

  
962

  
963
### PROJECTS ###
964
################
965

  
1174 966
class MemberJoinPolicy(models.Model):
1175 967
    policy = models.CharField(_('Policy'), max_length=255, unique=True, db_index=True)
1176 968
    description = models.CharField(_('Description'), max_length=80)
......
1185 977
    def __str__(self):
1186 978
        return self.policy
1187 979

  
1188
_auto_accept_join = False
1189
def get_auto_accept_join():
1190
    global _auto_accept_join
1191
    if _auto_accept_join is not False:
1192
        return _auto_accept_join
1193
    try:
1194
        auto_accept = MemberJoinPolicy.objects.get(policy='auto_accept')
1195
    except:
1196
        auto_accept = None
1197
    _auto_accept_join = auto_accept
1198
    return auto_accept
1199

  
1200
_closed_join = False
1201
def get_closed_join():
1202
    global _closed_join
1203
    if _closed_join is not False:
1204
        return _closed_join
1205
    try:
1206
        closed = MemberJoinPolicy.objects.get(policy='closed')
1207
    except:
1208
        closed = None
1209
    _closed_join = closed
1210
    return closed
1211

  
1212
_auto_accept_leave = False
1213
def get_auto_accept_leave():
1214
    global _auto_accept_leave
1215
    if _auto_accept_leave is not False:
1216
        return _auto_accept_leave
1217
    try:
1218
        auto_accept = MemberLeavePolicy.objects.get(policy='auto_accept')
1219
    except:
1220
        auto_accept = None
1221
    _auto_accept_leave = auto_accept
1222
    return auto_accept
1223

  
1224
_closed_leave = False
1225
def get_closed_leave():
1226
    global _closed_leave
1227
    if _closed_leave is not False:
1228
        return _closed_leave
1229
    try:
1230
        closed = MemberLeavePolicy.objects.get(policy='closed')
1231
    except:
1232
        closed = None
1233
    _closed_leave = closed
1234
    return closed
1235

  
1236

  
1237
### PROJECTS ###
1238
################
1239

  
1240

  
1241 980
def synced_model_metaclass(class_name, class_parents, class_attributes):
1242 981

  
1243 982
    new_attributes = {}
......
1940 1679
    reason  =   models.IntegerField()
1941 1680
    serial  =   models.BigIntegerField()
1942 1681

  
1943

  
1944
def filter_queryset_by_property(q, property):
1945
    """
1946
    Incorporate list comprehension for filtering querysets by property
1947
    since Queryset.filter() operates on the database level.
1948
    """
1949
    return (p for p in q if getattr(p, property, False))
1950

  
1951
def get_alive_projects():
1952
    return filter_queryset_by_property(
1953
        Project.objects.all(),
1954
        'is_alive'
1955
    )
1956

  
1957
def get_active_projects():
1958
    return filter_queryset_by_property(
1959
        Project.objects.all(),
1960
        'is_active'
1961
    )
1962

  
1963
def _create_object(model, **kwargs):
1964
    o = model.objects.create(**kwargs)
1965
    o.save()
1966
    return o
1967

  
1682
### SIGNALS ###
1683
################
1968 1684

  
1969 1685
def create_astakos_user(u):
1970 1686
    try:
......
1993 1709
    create_astakos_user(instance)
1994 1710
post_save.connect(user_post_save, sender=User)
1995 1711

  
1996

  
1997
# def astakosuser_pre_save(sender, instance, **kwargs):
1998
#     instance.aquarium_report = False
1999
#     instance.new = False
2000
#     try:
2001
#         db_instance = AstakosUser.objects.get(id=instance.id)
2002
#     except AstakosUser.DoesNotExist:
2003
#         # create event
2004
#         instance.aquarium_report = True
2005
#         instance.new = True
2006
#     else:
2007
#         get = AstakosUser.__getattribute__
2008
#         l = filter(lambda f: get(db_instance, f) != get(instance, f),
2009
#                    BILLING_FIELDS)
2010
#         instance.aquarium_report = True if l else False
2011
# pre_save.connect(astakosuser_pre_save, sender=AstakosUser)
2012

  
2013
# def set_default_group(user):
2014
#     try:
2015
#         default = AstakosGroup.objects.get(name='default')
2016
#         Membership(
2017
#             group=default, person=user, date_joined=datetime.now()).save()
2018
#     except AstakosGroup.DoesNotExist, e:
2019
#         logger.exception(e)
2020

  
1712
def astakosuser_pre_save(sender, instance, **kwargs):
1713
    instance.aquarium_report = False
1714
    instance.new = False
1715
    try:
1716
        db_instance = AstakosUser.objects.get(id=instance.id)
1717
    except AstakosUser.DoesNotExist:
1718
        # create event
1719
        instance.aquarium_report = True
1720
        instance.new = True
1721
    else:
1722
        get = AstakosUser.__getattribute__
1723
        l = filter(lambda f: get(db_instance, f) != get(instance, f),
1724
                   BILLING_FIELDS)
1725
        instance.aquarium_report = True if l else False
1726
pre_save.connect(astakosuser_pre_save, sender=AstakosUser)
2021 1727

  
2022 1728
def astakosuser_post_save(sender, instance, created, **kwargs):
2023
#     if instance.aquarium_report:
2024
#         report_user_event(instance, create=instance.new)
1729
    if instance.aquarium_report:
1730
        report_user_event(instance, create=instance.new)
2025 1731
    if not created:
2026 1732
        return
2027
#     set_default_group(instance)
2028 1733
    # TODO handle socket.error & IOError
2029 1734
    register_users((instance,))
2030 1735
post_save.connect(astakosuser_post_save, sender=AstakosUser)
......
2037 1742
post_save.connect(resource_post_save, sender=Resource)
2038 1743

  
2039 1744

  
2040
# def on_quota_disturbed(sender, users, **kwargs):
2041
# #     print '>>>', locals()
2042
#     if not users:
2043
#         return
2044
#     send_quota(users)
2045
#
2046
# quota_disturbed = Signal(providing_args=["users"])
2047
# quota_disturbed.connect(on_quota_disturbed)
2048

  
2049

  
2050
# def send_quota_disturbed(sender, instance, **kwargs):
2051
#     users = []
2052
#     extend = users.extend
2053
#     if sender == Membership:
2054
#         if not instance.group.is_enabled:
2055
#             return
2056
#         extend([instance.person])
2057
#     elif sender == AstakosUserQuota:
2058
#         extend([instance.user])
2059
#     elif sender == AstakosGroupQuota:
2060
#         if not instance.group.is_enabled:
2061
#             return
2062
#         extend(instance.group.astakosuser_set.all())
2063
#     elif sender == AstakosGroup:
2064
#         if not instance.is_enabled:
2065
#             return
2066
#     quota_disturbed.send(sender=sender, users=users)
2067
# post_delete.connect(send_quota_disturbed, sender=AstakosGroup)
2068
# post_delete.connect(send_quota_disturbed, sender=Membership)
2069
# post_save.connect(send_quota_disturbed, sender=AstakosUserQuota)
2070
# post_delete.connect(send_quota_disturbed, sender=AstakosUserQuota)
2071
# post_save.connect(send_quota_disturbed, sender=AstakosGroupQuota)
2072
# post_delete.connect(send_quota_disturbed, sender=AstakosGroupQuota)
2073

  
2074

  
2075 1745
def renew_token(sender, instance, **kwargs):
2076 1746
    if not instance.auth_token:
2077 1747
        instance.renew_token()

Also available in: Unified diff