Revision 0cc22d47 snf-astakos-app/astakos/im/models.py

b/snf-astakos-app/astakos/im/models.py
1043 1043
    start_date = models.DateTimeField()
1044 1044
    end_date = models.DateTimeField()
1045 1045
    member_accept_policy = models.ForeignKey(MemberAcceptPolicy)
1046
    member_reject_policy = models.ForeignKey(MemberRejectPolicy)
1046 1047
    limit_on_members_number = models.PositiveIntegerField(null=True,blank=True)
1047 1048
    resource_grants = models.ManyToManyField(
1048 1049
        Resource,
......
1084 1085
            uplimit = p.get('uplimit', 0)
1085 1086
            update = p.get('update', True)
1086 1087
            self.add_resource_policy(service, resource, uplimit, update)
1088
    
1089
    def validate_name(self):
1090
        """
1091
        Validate name uniqueness among all active projects.
1092
        """
1093
        alive_projects = list(get_alive_projects())
1094
        q = filter(
1095
            lambda p: p.definition.name == self.name and \
1096
                p.application.serial != self.projectapplication.serial,
1097
            alive_projects
1098
        )
1099
        if q:
1100
            raise ValidationError(
1101
                {'name': [_(astakos_messages.UNIQUE_PROJECT_NAME_CONSTRAIN_ERR)]}
1102
            )
1103

  
1087 1104

  
1088 1105
class ProjectResourceGrant(models.Model):
1089 1106
    objects = ExtendedManager()
......
1099 1116
    serial = models.CharField(
1100 1117
        primary_key=True,
1101 1118
        max_length=30,
1102
        unique=True,
1103
        default=uuid.uuid4().hex[:30]
1119
        unique=True
1104 1120
    )
1105 1121
    applicant = models.ForeignKey(
1106 1122
        AstakosUser,
......
1118 1134
        null=True,
1119 1135
        blank=True
1120 1136
    )
1137
    
1138
    def save(self):
1139
        if not self.serial:
1140
            self.serial = uuid.uuid4().hex[:30]
1141
        super(ProjectApplication, self).save()
1142

  
1143
    @staticmethod
1144
    def submit(definition, applicant, comments, precursor_application=None, commit=True):
1145
        if precursor_application and precursor_application.project.is_valid:
1146
            application = precursor_application.copy()
1147
            application.precursor_application = precursor_application
1148
        else:
1149
            application = ProjectApplication(owner=applicant)
1150
        application.definition = definition
1151
        application.applicant = applicant
1152
        application.comments = comments
1153
        application.issue_date = datetime.now()
1154
        if commit:
1155
            definition.save()
1156
            application.save()
1157
        if applicant.is_superuser:
1158
            self.approve_application()
1159
        notification = build_notification(
1160
            settings.SERVER_EMAIL,
1161
            [i[1] for i in settings.ADMINS],
1162
            _(GROUP_CREATION_SUBJECT) % {'group':application.definition.name},
1163
            _('An new project application identified by %(serial)s has been submitted.') % application.__dict__
1164
        )
1165
        notification.send()
1166
        return application
1121 1167

  
1122 1168
class Project(models.Model):
1123 1169
    serial = models.CharField(
1124
        _('username'),
1125 1170
        primary_key=True,
1126 1171
        max_length=30,
1127
        unique=True,
1128
        default=uuid.uuid4().hex[:30]
1172
        unique=True
1129 1173
    )
1130 1174
    application = models.OneToOneField(ProjectApplication, related_name='project')
1131 1175
    creation_date = models.DateTimeField()
......
1138 1182
        ProjectApplication, related_name='last_project', null=True, blank=True
1139 1183
    )
1140 1184
    
1185
    def save(self):
1186
        if not self.serial:
1187
            self.serial = uuid.uuid4().hex[:30]
1188
        super(ProjectApplication, self).save()
1189

  
1141 1190
    @property
1142 1191
    def definition(self):
1143 1192
        return self.application.definition
......
1213 1262
    
1214 1263
    @property
1215 1264
    def approved_members(self):
1216
        return [m.person for m in self.projectmembership_set.filter(is_accepted=True)]
1265
        return [m.person for m in self.projectmembership_set.filter(~Q(acceptance_date=None))]
1217 1266
        
1218 1267
    def sync(self, specific_members=()):
1219 1268
        if self.is_synchornized():
......
1237 1286
        created, m = ProjectMembership.objects.get_or_create(
1238 1287
            person=user, project=project
1239 1288
        )
1240
        if m.is_accepted:
1241
            return
1242
        if created:
1243
            m.issue_date = datetime.now()
1244
        
1245
        m.is_accepted = True
1246
        m.decision_date = datetime.now()
1247
        m.save()
1289
        m.accept()
1248 1290
        
1249
        # set membership_dirty flag
1250
        self.membership_dirty = True
1251
        self.save()
1252
        
1253
        rejected = self.sync([user])
1254
        if not rejected:
1255
            # if syncing was successful unset membership_dirty flag
1256
            self.membership_dirty = False
1257
            self.save()
1258
        
1259
        notification = build_notification(
1260
            settings.SERVER_EMAIL,
1261
            [user.email],
1262
            _('Your membership on project %(name)s has been accepted.') % project.definition.__dict__,
1263
            _('Your membership on project %(name)s has been accepted.') % project.definition.__dict__
1264
        )
1265
    
1266 1291
    def remove_member(self, user, request_user=None):
1267 1292
        if user.is_digit():
1268 1293
            user = _lookup_object(AstakosUser, id=user)
......
1272 1297
        if not self.is_alive:
1273 1298
            raise Exception(_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__)
1274 1299
        m = _lookup_object(ProjectMembership, person=user, project=project)
1275
        if not m.is_accepted:
1276
            return
1277
        m.is_accepted = False
1278
        m.decision_date = datetime.now()
1279
        m.save()
1300
        m.remove()
1280 1301
        
1281
        # set membership_dirty flag
1282
        self.membership_dirty = True
1283
        self.save()
1284
        
1285
        rejected = self.sync([user])
1286
        if not rejected:
1287
            # if syncing was successful unset membership_dirty flag
1288
            self.membership_dirty = False
1289
            self.save()
1290
            
1291
        notification = build_notification(
1292
            settings.SERVER_EMAIL,
1293
            [user.email],
1294
            _('Your membership on project %(name)s has been removed.') % project.definition.__dict__,
1295
            _('Your membership on project %(name)s has been removed.') % project.definition.__dict__
1296
        )
1297
        notification.send()
1298
            
1299

  
1300
    def validate_name(self):
1301
        """
1302
        Validate name uniqueness among all active projects.
1303
        """
1304
        alive_projects = list(get_alive_projects())
1305
        q = filter(
1306
            lambda p: p.definition.name == self.definition.name and \
1307
                p.application.serial != self.application.serial,
1308
            alive_projects
1309
        )
1310
        if q:
1311
            raise ValidationError(
1312
                {'name': [_(astakos_messages.UNIQUE_PROJECT_NAME_CONSTRAIN_ERR)]}
1313
            )
1314
    
1315
    @classmethod
1316
    def submit(definition, applicant, comments, precursor_application=None, commit=True):
1317
        if precursor_application and precursor_application.project.is_valid:
1318
            application = precursor_application.copy()
1319
            application.precursor_application = precursor_application
1320
        else:
1321
            application = ProjectApplication(owner=applicant)
1322
        application.definition = definition
1323
        application.applicant = applicant
1324
        application.comments = comments
1325
        application.issue_date = datetime.now()
1326
        if commit:
1327
            definition.save()
1328
            application.save()
1329
        if applicant.is_superuser():
1330
            self.approve_application()
1331
        notification = build_notification(
1332
            settings.SERVER_EMAIL,
1333
            [i[1] for i in settings.ADMINS],
1334
            _(GROUP_CREATION_SUBJECT) % {'group':application.definition.name},
1335
            _('An new project application identified by %(serial)s has been submitted.') % application.__dict__
1336
        )
1337
        notification.send()
1338
        return application
1339
    
1340 1302
    def approve(self, approval_user=None):
1341 1303
        """
1342 1304
        If approval_user then during owner membership acceptance
......
1412 1374
        )
1413 1375
        notification.send()
1414 1376

  
1377
class ProjectMembership(models.Model):
1378
    person = models.ForeignKey(AstakosUser)
1379
    project = models.ForeignKey(Project)
1380
    request_date = models.DateField(default=datetime.now())
1381
    acceptance_date = models.DateField(null=True, db_index=True)
1415 1382

  
1383
    class Meta:
1384
        unique_together = ("person", "project")
1385
    
1386
    def accept(self):
1387
        if self.acceptance_date:
1388
            return
1389
        self.acceptance_date = datetime.now()
1390
        self.save()
1391
        notification = build_notification(
1392
            settings.SERVER_EMAIL,
1393
            [self.person.email],
1394
            _('Your membership on project %(name)s has been accepted.') % self.project.definition.__dict__,
1395
            _('Your membership on project %(name)s has been accepted.') % self.project.definition.__dict__
1396
        ).send()
1397
        self.sync()
1398
    
1399
    def reject(self):
1400
        history_item = ProjectMembershipHistory(
1401
            serial=self.serial,
1402
            person=self.person,
1403
            project=self.project,
1404
            request_date=self.request_date,
1405
            rejection_date=datetime.now()
1406
        ).save()
1407
        self.delete()
1408
        notification = build_notification(
1409
            settings.SERVER_EMAIL,
1410
            [self.person.email],
1411
            _('Your membership on project %(name)s has been rejected.') % self.project.definition.__dict__,
1412
            _('Your membership on project %(name)s has been rejected.') % self.project.definition.__dict__
1413
        ).send()
1414
    
1415
    def remove(self):
1416
        history_item = ProjectMembershipHistory(
1417
            id=self.id,
1418
            person=self.person,
1419
            project=self.project,
1420
            request_date=self.request_date,
1421
            removal_date=datetime.now()
1422
        ).save()
1423
        self.delete()
1424
        notification = build_notification(
1425
            settings.SERVER_EMAIL,
1426
            [self.person.email],
1427
            _('Your membership on project %(name)s has been removed.') % self.project.definition.__dict__,
1428
            _('Your membership on project %(name)s has been removed.') % self.project.definition.__dict__
1429
        ).send()
1430
        self.sync()
1431
    
1432
    def sync(self):
1433
        # set membership_dirty flag
1434
        self.project.membership_dirty = True
1435
        self.project.save()
1436
        
1437
        rejected = self.sync([self])
1438
        if not rejected:
1439
            # if syncing was successful unset membership_dirty flag
1440
            self.membership_dirty = False
1441
            self.save()
1442
        
1416 1443

  
1417
class ProjectMembership(models.Model):
1444
class ProjectMembershipHistory(models.Model):
1418 1445
    person = models.ForeignKey(AstakosUser)
1419 1446
    project = models.ForeignKey(Project)
1420
    issue_date = models.DateField(default=datetime.now())
1421
    decision_date = models.DateField(null=True, db_index=True)
1422
    is_accepted = models.BooleanField(default=False)
1447
    request_date = models.DateField(default=datetime.now())
1448
    removal_date = models.DateField(null=True)
1449
    rejection_date = models.DateField(null=True)
1423 1450

  
1424 1451
    class Meta:
1425 1452
        unique_together = ("person", "project")
1426 1453

  
1454

  
1427 1455
def filter_queryset_by_property(q, property):
1428 1456
    """
1429 1457
    Incorporate list comprehension for filtering querysets by property
......
1470 1498
        o.save()
1471 1499
    return o
1472 1500

  
1473
def list_applications():
1474
    return ProjectApplication.objects.all()
1475

  
1476

  
1477
def list_projects(filter_property=None):
1478
    if filter_property:
1479
        return filter_queryset_by_property(
1480
            Project.objects.all(),
1481
            filter_property
1482
        )
1483
    return Project.objects.all()
1484

  
1485

  
1486
def synchonize_project(serial):
1487
    project = _lookup_object(Project, serial=serial)
1488
    return project.sync()
1501
# def list_applications():
1502
#     return ProjectApplication.objects.all()
1503
# 
1504
# 
1505
# def list_projects(filter_property=None):
1506
#     if filter_property:
1507
#         return filter_queryset_by_property(
1508
#             Project.objects.all(),
1509
#             filter_property
1510
#         )
1511
#     return Project.objects.all()
1512
# 
1513
# 
1514
# def synchonize_project(serial):
1515
#     project = _lookup_object(Project, serial=serial)
1516
#     return project.sync()
1489 1517

  
1490 1518

  
1491 1519
def create_astakos_user(u):

Also available in: Unified diff