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