Revision b8f05f8d

b/snf-astakos-app/astakos/im/messages.py
111 111
FEEDBACK_SEND_ERR                       =   EMAIL_SEND_ERR % 'feedback'
112 112
CHANGE_EMAIL_SEND_ERR                   =   EMAIL_SEND_ERR % 'feedback'
113 113
NOTIFICATION_SEND_ERR                   =   EMAIL_SEND_ERR % 'notification'
114
DETAILED_NOTIFICATION_SEND_ERR          =   'Failed to send %(subject)s notification to %(recipients)s.'
114 115

  
115 116
MISSING_NEXT_PARAMETER                  =   'No next parameter'
116 117

  
......
137 138
NOT_ALIVE_PROJECT                       =   'Project %(id)s is not alive.'
138 139
NOT_ALLOWED                             =   'You do not have the permissions to perform this action.'
139 140
MEMBER_NUMBER_LIMIT_REACHED             =   'Maximum participant number has been reached.'
140
MEMBER_JOIN_POLICY_CLOSED               =   'The project member join policy is cloesd.'
141
MEMBER_JOIN_POLICY_CLOSED               =   'The project member join policy is closed.'
141 142
MEMBER_LEAVE_POLICY_CLOSED              =   'The project member leave policy is closed.'
142 143
NOT_MEMBERSHIP_REQUEST                  =   'There is no such a membership request.'
143 144
MEMBERSHIP_REQUEST_EXISTS               =   'There is alreary such a membership request.'
......
145 146
ADD_PROJECT_MEMBERS_Q_HELP              =   'Add comma separated user emails, eg. user1@user.com, user2@user.com'
146 147
MISSING_IDENTIFIER                      =   'Missing identifier.'
147 148
UNKNOWN_IDENTIFIER                      =   'Unknown identidier.'
148
PENDING_MEMBERSHIP_LEAVE                =   'Your request is pending acceptio.'
149
PENDING_MEMBERSHIP_LEAVE                =   'Your request is pending acception.'
b/snf-astakos-app/astakos/im/models.py
474 474
            p = m.project
475 475
            if not p.is_active:
476 476
                continue
477
            grants = p.application.definition.projectresourcegrant_set.all()
477
            grants = p.current_application.definition.projectresourcegrant_set.all()
478 478
            for g in grants:
479 479
                d[str(g.resource)] += g.member_limit or inf
480 480
        # TODO set default for remaining
......
1153 1153
        """
1154 1154
        q = list(get_alive_projects())
1155 1155
        q = filter(lambda p: p.definition.name == self.name , q)
1156
        q = filter(lambda p: p.application.id != self.projectapplication.id, q)
1156
        q = filter(lambda p: p.current_application.id != self.projectapplication.id, q)
1157 1157
        if self.projectapplication.precursor_application:
1158
            q = filter(lambda p: p.application.id != \
1158
            q = filter(lambda p: p.current_application.id != \
1159 1159
                self.projectapplication.precursor_application.id, q)
1160 1160
        if q:
1161 1161
            raise ValidationError(
......
1229 1229
        application.state = PENDING
1230 1230
        application.save()
1231 1231
        application.definition.resource_policies = resource_policies
1232
        
1233
        try:
1234
            notification = build_notification(
1235
                settings.SERVER_EMAIL,
1236
                [i[1] for i in settings.ADMINS],
1237
                _(PROJECT_CREATION_SUBJECT) % application.definition.__dict__,
1238
                template='im/projects/project_creation_notification.txt',
1239
                dictionary={'object':application}
1240
            ).send()
1241
        except NotificationError, e:
1242
            logger.error(e.messages)
1232 1243

  
1233
        notification = build_notification(
1234
            settings.SERVER_EMAIL,
1235
            [i[1] for i in settings.ADMINS],
1236
            _(PROJECT_CREATION_SUBJECT) % application.definition.__dict__,
1237
            template='im/projects/project_creation_notification.txt',
1238
            dictionary={'object':application}
1239
        )
1240
        notification.send()
1241 1244
        return application
1242 1245

  
1243 1246
    def approve(self, approval_user=None):
......
1246 1249
        it is checked whether the request_user is eligible.
1247 1250

  
1248 1251
        Raises:
1249
            ValidationError: if there is other alive project with the same name
1250

  
1252
            PermissionDenied
1251 1253
        """
1252 1254
        try:
1253 1255
            self.definition.validate_name()
......
1263 1265
        except:
1264 1266
            project = Project()
1265 1267
            project.creation_date = now
1266
            project.accept_member(self.owner, approval_user)
1267 1268

  
1268 1269
        project.last_application_approved = self
1269 1270
        project.last_approval_date = now
1270 1271
        project.save()
1272
        project.accept_member(self.owner, approval_user)
1271 1273

  
1272 1274
        p = precursor
1273 1275
        while p:
......
1278 1280
        self.state = APPROVED
1279 1281
        self.save()
1280 1282

  
1281
        transaction.commit()
1282

  
1283
        notification = build_notification(
1284
            settings.SERVER_EMAIL,
1285
            [self.owner.email],
1286
            _(PROJECT_APPROVED_SUBJECT) % self.definition.__dict__,
1287
            template='im/projects/project_approval_notification.txt',
1288
            dictionary={'object':self}
1289
        )
1290
        notification.send()
1283
        if transaction.is_managed():
1284
            transaction.commit()
1291 1285

  
1292 1286
        rejected = self.project.sync()
1293
        if not rejected:
1294
            project.application = self
1295
            project.save()
1287
        
1288
        try:
1289
            notification = build_notification(
1290
                settings.SERVER_EMAIL,
1291
                [self.owner.email],
1292
                _(PROJECT_APPROVED_SUBJECT) % self.definition.__dict__,
1293
                template='im/projects/project_approval_notification.txt',
1294
                dictionary={'object':self}
1295
            ).send()
1296
        except NotificationError, e:
1297
            logger.error(e.messages)
1296 1298

  
1297 1299

  
1298 1300
class Project(models.Model):
1299 1301
    application = models.OneToOneField(
1300
        ProjectApplication, related_name='project', null=True, blank=True)
1302
        ProjectApplication, related_name='project', null=True)
1301 1303
    creation_date = models.DateTimeField()
1302 1304
    last_approval_date = models.DateTimeField(null=True)
1303 1305
    termination_start_date = models.DateTimeField(null=True)
......
1307 1309
    last_application_approved = models.OneToOneField(
1308 1310
        ProjectApplication, related_name='last_project')
1309 1311
    
1312
    @property
1313
    def current_application(self):
1314
        return self.application or self.last_application_approved
1310 1315
    
1311 1316
    @property
1312 1317
    def definition(self):
1313
        return self.application.definition
1318
        return self.current_application.definition
1314 1319

  
1315 1320
    @property
1316 1321
    def violated_members_number_limit(self):
......
1375 1380
            return
1376 1381
        members = specific_members or self.approved_members
1377 1382
        c, rejected = send_quota(self.approved_members)
1383
        if not rejected:
1384
            self.application = self.last_application_approved
1385
            self.save()
1378 1386
        return rejected
1379 1387
    
1380 1388
    def accept_member(self, user, request_user=None):
......
1436 1444
            self.termination_date = datetime.now()
1437 1445
            self.save()
1438 1446
            
1439
        notification = build_notification(
1440
            settings.SERVER_EMAIL,
1441
            [self.application.owner.email],
1442
            _(PROJECT_TERMINATION_SUBJECT) % self.definition.__dict__,
1443
            template='im/projects/project_termination_notification.txt',
1444
            dictionary={'object':self.application}
1445
        )
1446
        notification.send()
1447
        try:
1448
            notification = build_notification(
1449
                settings.SERVER_EMAIL,
1450
                [self.current_application.owner.email],
1451
                _(PROJECT_TERMINATION_SUBJECT) % self.definition.__dict__,
1452
                template='im/projects/project_termination_notification.txt',
1453
                dictionary={'object':self.current_application}
1454
            ).send()
1455
        except NotificationError, e:
1456
            logger.error(e.messages)
1447 1457

  
1448 1458
    def suspend(self):
1449 1459
        self.last_approval_date = None
1450 1460
        self.save()
1451 1461
        self.sync()
1452
        notification = build_notification(
1453
            settings.SERVER_EMAIL,
1454
            [self.application.owner.email],
1455
            _(PROJECT_SUSPENSION_SUBJECT) % self.definition.__dict__,
1456
            template='im/projects/project_suspension_notification.txt',
1457
            dictionary={'object':self.application}
1458
        )
1459
        notification.send()
1462

  
1463
        try:
1464
            notification = build_notification(
1465
                settings.SERVER_EMAIL,
1466
                [self.current_application.owner.email],
1467
                _(PROJECT_SUSPENSION_SUBJECT) % self.definition.__dict__,
1468
                template='im/projects/project_suspension_notification.txt',
1469
                dictionary={'object':self.current_application}
1470
            ).send()
1471
        except NotificationError, e:
1472
            logger.error(e.messages)
1460 1473

  
1461 1474
class ProjectMembership(models.Model):
1462 1475
    person = models.ForeignKey(AstakosUser)
......
1472 1485
        """
1473 1486
            Raises:
1474 1487
                django.exception.PermissionDenied
1475
                astakos.im.notifications.NotificationError
1476 1488
        """
1477 1489
        try:
1478 1490
            if request_user and \
1479
                (not self.project.application.owner == request_user and \
1491
                (not self.project.current_application.owner == request_user and \
1480 1492
                    not request_user.is_superuser):
1481 1493
                raise PermissionDenied(_(astakos_messages.NOT_ALLOWED))
1482 1494
            if not self.project.is_alive:
......
1491 1503
            return
1492 1504
        self.acceptance_date = datetime.now()
1493 1505
        self.save()
1494
        notification = build_notification(
1495
            settings.SERVER_EMAIL,
1496
            [self.person.email],
1497
            _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1498
            template='im/projects/project_membership_change_notification.txt',
1499
            dictionary={'object':self.project.application, 'action':'accepted'}
1500
        ).send()
1501 1506
        self.sync()
1507

  
1508
        try:
1509
            notification = build_notification(
1510
                settings.SERVER_EMAIL,
1511
                [self.person.email],
1512
                _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1513
                template='im/projects/project_membership_change_notification.txt',
1514
                dictionary={'object':self.project.current_application, 'action':'accepted'}
1515
            ).send()
1516
        except NotificationError, e:
1517
            logger.error(e.messages)
1502 1518
    
1503 1519
    def reject(self, request_user=None):
1504 1520
        """
1505 1521
            Raises:
1506
                django.exception.PermissionDenied,
1507
                astakos.im.notifications.NotificationError
1522
                django.exception.PermissionDenied
1508 1523
        """
1509 1524
        if request_user and \
1510
            (not self.project.application.owner == request_user and \
1525
            (not self.project.current_application.owner == request_user and \
1511 1526
                not request_user.is_superuser):
1512 1527
            raise PermissionDenied(_(astakos_messages.NOT_ALLOWED))
1513 1528
        if not self.project.is_alive:
......
1520 1535
        )
1521 1536
        self.delete()
1522 1537
        history_item.save()
1523
        notification = build_notification(
1524
            settings.SERVER_EMAIL,
1525
            [self.person.email],
1526
            _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1527
            template='im/projects/project_membership_change_notification.txt',
1528
            dictionary={'object':self.project.application, 'action':'rejected'}
1529
        ).send()
1530
    
1538

  
1539
        try:
1540
            notification = build_notification(
1541
                settings.SERVER_EMAIL,
1542
                [self.person.email],
1543
                _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1544
                template='im/projects/project_membership_change_notification.txt',
1545
                dictionary={'object':self.project.current_application, 'action':'rejected'}
1546
            ).send()
1547
        except NotificationError, e:
1548
            logger.error(e.messages)
1549

  
1531 1550
    def remove(self, request_user=None):
1532 1551
        """
1533 1552
            Raises:
1534 1553
                django.exception.PermissionDenied
1535
                astakos.im.notifications.NotificationError
1536 1554
        """
1537 1555
        if request_user and \
1538
            (not self.project.application.owner == request_user and \
1556
            (not self.project.current_application.owner == request_user and \
1539 1557
                not request_user.is_superuser):
1540 1558
            raise PermissionDenied(_(astakos_messages.NOT_ALLOWED))
1541 1559
        if not self.project.is_alive:
......
1549 1567
        )
1550 1568
        self.delete()
1551 1569
        history_item.save()
1552
        notification = build_notification(
1553
            settings.SERVER_EMAIL,
1554
            [self.person.email],
1555
            _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1556
            template='im/projects/project_membership_change_notification.txt',
1557
            dictionary={'object':self.project.application, 'action':'removed'}
1558
        ).send()
1559 1570
        self.sync()
1571

  
1572
        try:
1573
            notification = build_notification(
1574
                settings.SERVER_EMAIL,
1575
                [self.person.email],
1576
                _(PROJECT_MEMBERSHIP_CHANGE_SUBJECT) % self.project.definition.__dict__,
1577
                template='im/projects/project_membership_change_notification.txt',
1578
                dictionary={'object':self.project.current_application, 'action':'removed'}
1579
            ).send()
1580
        except NotificationError, e:
1581
            logger.error(e.messages)
1560 1582
    
1561 1583
    def leave(self):
1562
        leave_policy = self.project.application.definition.member_leave_policy
1584
        leave_policy = self.project.current_application.definition.member_leave_policy
1563 1585
        if leave_policy == get_auto_accept_leave():
1564 1586
            self.remove()
1565 1587
        else:
......
1727 1749
def check_closed_join_membership_policy(sender, instance, **kwargs):
1728 1750
    if instance.id:
1729 1751
        return
1730
    if instance.person == instance.project.application.owner:
1752
    if instance.person == instance.project.current_application.owner:
1731 1753
        return
1732
    join_policy = instance.project.application.definition.member_join_policy
1754
    join_policy = instance.project.current_application.definition.member_join_policy
1733 1755
    if join_policy == get_closed_join():
1734 1756
        raise PermissionDenied(_(astakos_messages.MEMBER_JOIN_POLICY_CLOSED))
1735 1757
pre_save.connect(check_closed_join_membership_policy, sender=ProjectMembership)
......
1738 1760
def check_auto_accept_join_membership_policy(sender, instance, created, **kwargs):
1739 1761
    if not created:
1740 1762
        return
1741
    join_policy = instance.project.application.definition.member_join_policy
1763
    join_policy = instance.project.current_application.definition.member_join_policy
1742 1764
    if join_policy == get_auto_accept_join() and not instance.acceptance_date:
1743 1765
        instance.accept()
1744 1766
post_save.connect(check_auto_accept_join_membership_policy, sender=ProjectMembership)
b/snf-astakos-app/astakos/im/views.py
99 99
)
100 100
#from astakos.im.tasks import request_billing
101 101
from astakos.im.api.callpoint import AstakosCallpoint
102
from astakos.im.notifications import NotificationError
103 102

  
104 103
import astakos.im.messages as astakos_messages
105 104
from astakos.im import settings
......
1479 1478
            extra_context=extra_context, post_save_redirect='/im/project/list/',
1480 1479
            form_class=ProjectApplicationForm)
1481 1480
        return r
1482
    except NotificationError, e:
1481
    except BaseException, e:
1482
        logger.exception(e)
1483
        messages.error(request, _(astakos_messages.GENERIC_ERROR))
1483 1484
        rollback = True
1484
        messages.error(request, e.message)
1485 1485
        return render_response(
1486 1486
            'im/projects/projectapplication_form.html',
1487 1487
            sorting = 'definition__name',
......
1665 1665
        messages.error(request, msg)
1666 1666
    except PermissionDenied, e:
1667 1667
        messages.error(request, e)
1668
    except NotificationError, e:
1668
    except BaseException, e:
1669
        logger.exception(e)
1670
        messages.error(request, _(astakos_messages.GENERIC_ERROR))
1669 1671
        rollback = True
1670
        messages.error(request, e)
1671 1672
    else:
1672 1673
        return project_detail(request, id)
1673 1674
    finally:
......
1698 1699
        else:
1699 1700
            try:
1700 1701
                func(request, m)
1701
            except (NotificationError, PermissionDenied), e:
1702
            except PermissionDenied, e:
1702 1703
                messages.error(request, e)
1704
            except BaseException, e:
1705
                logger.exception(e)
1706
                messages.error(_(astakos_messages.GENERIC_ERROR ))
1703 1707
                rollback = True
1704 1708
        finally:
1705 1709
            if rollback:

Also available in: Unified diff