Revision f12bcb3d

b/snf-astakos-app/astakos/im/forms.py
44 44
from django.utils.encoding import smart_str
45 45
from django.db import transaction
46 46
from django.core import validators
47
from django.core.exceptions import PermissionDenied
48 47

  
49 48
from synnefo_branding.utils import render_to_string
50 49
from synnefo.lib import join_urls
......
53 52
from astakos.im import presentation
54 53
from astakos.im.widgets import DummyWidget, RecaptchaWidget
55 54
from astakos.im.functions import send_change_email, submit_application, \
56
    accept_membership_project_checks
55
    accept_membership_project_checks, ProjectError
57 56

  
58 57
from astakos.im.util import reserved_verified_email, model_to_dict
59 58
from astakos.im import auth_providers
......
969 968
    def clean(self):
970 969
        try:
971 970
            accept_membership_project_checks(self.project, self.request_user)
972
        except PermissionDenied, e:
971
        except ProjectError as e:
973 972
            raise forms.ValidationError(e)
974 973

  
975 974
        q = self.cleaned_data.get('q') or ''
b/snf-astakos-app/astakos/im/functions.py
38 38
from django.core.mail import send_mail, get_connection
39 39
from django.core.urlresolvers import reverse
40 40
from django.contrib.auth import login as auth_login, logout as auth_logout
41
from django.core.exceptions import PermissionDenied
42 41
from django.db.models import Q
43 42

  
44 43
from synnefo_branding.utils import render_to_string
......
244 243

  
245 244
### PROJECT FUNCTIONS ###
246 245

  
246

  
247
class ProjectError(Exception):
248
    pass
249

  
250

  
251
class ProjectNotFound(ProjectError):
252
    pass
253

  
254

  
255
class ProjectForbidden(ProjectError):
256
    pass
257

  
258

  
259
class ProjectBadRequest(ProjectError):
260
    pass
261

  
262

  
263
class ProjectConflict(ProjectError):
264
    pass
265

  
247 266
AUTO_ACCEPT_POLICY = 1
248 267
MODERATED_POLICY = 2
249 268
CLOSED_POLICY = 3
......
264 283
        return Project.objects.get(id=project_id)
265 284
    except Project.DoesNotExist:
266 285
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
267
        raise IOError(m)
286
        raise ProjectNotFound(m)
268 287

  
269 288

  
270 289
def get_project_for_update(project_id):
......
272 291
        return Project.objects.get_for_update(id=project_id)
273 292
    except Project.DoesNotExist:
274 293
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
275
        raise IOError(m)
294
        raise ProjectNotFound(m)
276 295

  
277 296

  
278 297
def get_project_of_application_for_update(app_id):
......
285 304
        return ProjectApplication.objects.get(id=application_id)
286 305
    except ProjectApplication.DoesNotExist:
287 306
        m = _(astakos_messages.UNKNOWN_PROJECT_APPLICATION_ID) % application_id
288
        raise IOError(m)
307
        raise ProjectNotFound(m)
289 308

  
290 309

  
291 310
def get_project_of_membership_for_update(memb_id):
......
298 317
        return AstakosUser.objects.get(id=user_id)
299 318
    except AstakosUser.DoesNotExist:
300 319
        m = _(astakos_messages.UNKNOWN_USER_ID) % user_id
301
        raise IOError(m)
320
        raise ProjectNotFound(m)
302 321

  
303 322

  
304 323
def get_user_by_uuid(uuid):
......
306 325
        return AstakosUser.objects.get(uuid=uuid)
307 326
    except AstakosUser.DoesNotExist:
308 327
        m = _(astakos_messages.UNKNOWN_USER_ID) % uuid
309
        raise IOError(m)
328
        raise ProjectNotFound(m)
310 329

  
311 330

  
312 331
def get_membership(project_id, user_id):
......
315 334
        return objs.get(project__id=project_id, person__id=user_id)
316 335
    except ProjectMembership.DoesNotExist:
317 336
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
318
        raise IOError(m)
337
        raise ProjectNotFound(m)
319 338

  
320 339

  
321 340
def get_membership_by_id(memb_id):
......
324 343
        return objs.get(id=memb_id)
325 344
    except ProjectMembership.DoesNotExist:
326 345
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
327
        raise IOError(m)
346
        raise ProjectNotFound(m)
328 347

  
329 348

  
330 349
def checkAllowed(entity, request_user, admin_only=False):
......
343 362
        return
344 363

  
345 364
    m = _(astakos_messages.NOT_ALLOWED)
346
    raise PermissionDenied(m)
365
    raise ProjectForbidden(m)
347 366

  
348 367

  
349 368
def checkAlive(project):
350 369
    if not project.is_alive:
351 370
        m = _(astakos_messages.NOT_ALIVE_PROJECT) % project.id
352
        raise PermissionDenied(m)
371
        raise ProjectConflict(m)
353 372

  
354 373

  
355 374
def accept_membership_project_checks(project, request_user):
......
359 378
    join_policy = project.application.member_join_policy
360 379
    if join_policy == CLOSED_POLICY:
361 380
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
362
        raise PermissionDenied(m)
381
        raise ProjectConflict(m)
363 382

  
364 383
    if project.violates_members_limit(adding=1):
365 384
        m = _(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED)
366
        raise PermissionDenied(m)
385
        raise ProjectConflict(m)
367 386

  
368 387

  
369 388
def accept_membership_checks(membership, request_user):
370 389
    if not membership.can_accept():
371 390
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
372
        raise PermissionDenied(m)
391
        raise ProjectConflict(m)
373 392

  
374 393
    project = membership.project
375 394
    accept_membership_project_checks(project, request_user)
......
392 411
def reject_membership_checks(membership, request_user):
393 412
    if not membership.can_reject():
394 413
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
395
        raise PermissionDenied(m)
414
        raise ProjectConflict(m)
396 415

  
397 416
    project = membership.project
398 417
    checkAllowed(project, request_user)
......
415 434
def cancel_membership_checks(membership, request_user):
416 435
    if not membership.can_cancel():
417 436
        m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST)
418
        raise PermissionDenied(m)
437
        raise ProjectConflict(m)
419 438

  
420 439
    if membership.person != request_user:
421
        raise PermissionDenied()
440
        msg = _(astakos_messages.NOT_ALLOWED)
441
        raise ProjectForbidden(msg)
422 442

  
423 443
    project = membership.project
424 444
    checkAlive(project)
......
436 456
def remove_membership_checks(membership, request_user=None):
437 457
    if not membership.can_remove():
438 458
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
439
        raise PermissionDenied(m)
459
        raise ProjectConflict(m)
440 460

  
441 461
    project = membership.project
442 462
    checkAllowed(project, request_user)
......
445 465
    leave_policy = project.application.member_leave_policy
446 466
    if leave_policy == CLOSED_POLICY:
447 467
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
448
        raise PermissionDenied(m)
468
        raise ProjectConflict(m)
449 469

  
450 470

  
451 471
def remove_membership(memb_id, request_user=None):
......
464 484

  
465 485
def enroll_member(project_id, user, request_user=None):
466 486
    project = get_project_for_update(project_id)
487
    try:
488
        project = get_project_for_update(project_id)
489
    except ProjectNotFound as e:
490
        raise ProjectConflict(e.message)
467 491
    accept_membership_project_checks(project, request_user)
468 492

  
469 493
    try:
470 494
        membership = get_membership(project_id, user.id)
471 495
        if not membership.can_enroll():
472 496
            m = _(astakos_messages.MEMBERSHIP_ACCEPTED)
473
            raise PermissionDenied(m)
497
            raise ProjectConflict(m)
474 498
        membership.join()
475
    except IOError:
499
    except ProjectNotFound:
476 500
        membership = new_membership(project, user)
477 501

  
478 502
    membership.accept()
......
487 511
def leave_project_checks(membership, request_user):
488 512
    if not membership.can_leave():
489 513
        m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP)
490
        raise PermissionDenied(m)
514
        raise ProjectConflict(m)
491 515

  
492 516
    if membership.person != request_user:
493
        raise PermissionDenied()
517
        msg = _(astakos_messages.NOT_ALLOWED)
518
        raise ProjectForbidden(msg)
494 519

  
495 520
    project = membership.project
496 521
    checkAlive(project)
......
498 523
    leave_policy = project.application.member_leave_policy
499 524
    if leave_policy == CLOSED_POLICY:
500 525
        m = _(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)
501
        raise PermissionDenied(m)
526
        raise ProjectConflict(m)
502 527

  
503 528

  
504 529
def can_leave_request(project, user):
......
507 532
        return False
508 533
    try:
509 534
        leave_project_checks(m, user)
510
    except PermissionDenied:
535
    except ProjectError:
511 536
        return False
512 537
    return True
513 538

  
......
539 564
    join_policy = project.application.member_join_policy
540 565
    if join_policy == CLOSED_POLICY:
541 566
        m = _(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)
542
        raise PermissionDenied(m)
567
        raise ProjectConflict(m)
543 568

  
544 569

  
545 570
def can_join_request(project, user):
546 571
    try:
547 572
        join_project_checks(project)
548
    except PermissionDenied:
573
    except ProjectError:
549 574
        return False
550 575

  
551 576
    m = user.get_membership(project)
......
568 593
        membership = get_membership(project.id, request_user.id)
569 594
        if not membership.can_join():
570 595
            msg = _(astakos_messages.MEMBERSHIP_ASSOCIATED)
571
            raise PermissionDenied(msg)
596
            raise ProjectConflict(msg)
572 597
        membership.join()
573
    except IOError:
598
    except ProjectNotFound:
574 599
        membership = new_membership(project, request_user)
575 600

  
576 601
    join_policy = project.application.member_join_policy
......
602 627
        try:
603 628
            check(membership, request_user)
604 629
            allowed.append(action)
605
        except PermissionDenied:
630
        except ProjectError:
606 631
            pass
607 632
    return allowed
608 633

  
......
630 655
             not request_user.is_superuser
631 656
             and not request_user.is_project_admin())):
632 657
            m = _(astakos_messages.NOT_ALLOWED)
633
            raise PermissionDenied(m)
658
            raise ProjectForbidden(m)
634 659

  
635 660
    policies = validate_resource_policies(resources)
636 661

  
......
638 663
    ok, limit = qh_add_pending_app(owner, project, force)
639 664
    if not ok:
640 665
        m = _(astakos_messages.REACHED_PENDING_APPLICATION_LIMIT) % limit
641
        raise PermissionDenied(m)
666
        raise ProjectConflict(m)
642 667

  
643 668
    application = ProjectApplication(
644 669
        applicant=request_user,
......
693 718
    found = resource_d.keys()
694 719
    nonex = [name for name in resource_names if name not in found]
695 720
    if nonex:
696
        raise ValueError("Malformed resource policies")
721
        raise ProjectBadRequest("Malformed resource policies")
697 722

  
698 723
    pols = []
699 724
    for resource_name, specs in policies.iteritems():
......
701 726
        m_capacity = specs.get("member_capacity")
702 727

  
703 728
        if p_capacity is not None and not isinstance(p_capacity, (int, long)):
704
            raise ValueError("Malformed resource policies")
729
            raise ProjectBadRequest("Malformed resource policies")
705 730
        if not isinstance(m_capacity, (int, long)):
706
            raise ValueError("Malformed resource policies")
731
            raise ProjectBadRequest("Malformed resource policies")
707 732
        pols.append((resource_d[resource_name], m_capacity, p_capacity))
708 733
    return pols
709 734

  
......
724 749
    if not application.can_cancel():
725 750
        m = _(astakos_messages.APPLICATION_CANNOT_CANCEL %
726 751
              (application.id, application.state_display()))
727
        raise PermissionDenied(m)
752
        raise ProjectConflict(m)
728 753

  
729 754
    qh_release_pending_app(application.owner)
730 755

  
......
740 765
    if not application.can_dismiss():
741 766
        m = _(astakos_messages.APPLICATION_CANNOT_DISMISS %
742 767
              (application.id, application.state_display()))
743
        raise PermissionDenied(m)
768
        raise ProjectConflict(m)
744 769

  
745 770
    application.dismiss()
746 771
    logger.info("%s has been dismissed." % (application.log_display))
......
755 780
    if not application.can_deny():
756 781
        m = _(astakos_messages.APPLICATION_CANNOT_DENY %
757 782
              (application.id, application.state_display()))
758
        raise PermissionDenied(m)
783
        raise ProjectConflict(m)
759 784

  
760 785
    qh_release_pending_app(application.owner)
761 786

  
......
775 800
            m = (_("cannot approve: project with name '%s' "
776 801
                   "already exists (id: %s)") %
777 802
                 (new_project_name, conflicting_project.id))
778
            raise PermissionDenied(m)  # invalid argument
803
            raise ProjectConflict(m)  # invalid argument
779 804
    except Project.DoesNotExist:
780 805
        pass
781 806

  
......
789 814
    if not application.can_approve():
790 815
        m = _(astakos_messages.APPLICATION_CANNOT_APPROVE %
791 816
              (application.id, application.state_display()))
792
        raise PermissionDenied(m)
817
        raise ProjectConflict(m)
793 818

  
794 819
    check_conflicting_projects(application)
795 820

  
......
853 878

  
854 879
    if not project.is_suspended:
855 880
        m = _(astakos_messages.NOT_SUSPENDED_PROJECT) % project.id
856
        raise PermissionDenied(m)
881
        raise ProjectConflict(m)
857 882

  
858 883
    project.resume()
859 884
    qh_sync_project(project)
b/snf-astakos-app/astakos/im/views/projects.py
63 63
    reject_membership, remove_membership, cancel_membership, leave_project, \
64 64
    join_project, enroll_member, can_join_request, can_leave_request, \
65 65
    get_related_project_id, approve_application, \
66
    deny_application, cancel_application, dismiss_application
66
    deny_application, cancel_application, dismiss_application, ProjectError
67 67
from astakos.im import settings
68 68
from astakos.im.util import redirect_back
69 69
from astakos.im.views.util import render_response, _create_object, \
......
135 135
            form_class=ProjectApplicationForm,
136 136
            msg=_("The %(verbose_name)s has been received and "
137 137
                  "is under consideration."))
138
    except (IOError, PermissionDenied) as e:
138
    except ProjectError as e:
139 139
        messages.error(request, e)
140 140

  
141 141

  
......
187 187
        application_id = int(application_id)
188 188
        chain_id = get_related_project_id(application_id)
189 189
        cancel_application(application_id, request.user)
190
    except (IOError, PermissionDenied), e:
190
    except ProjectError as e:
191 191
        messages.error(request, e)
192 192

  
193 193
    else:
......
265 265
            form_class=ProjectApplicationForm,
266 266
            msg=_("The %(verbose_name)s has been received and is under "
267 267
                  "consideration."))
268
    except (IOError, PermissionDenied) as e:
268
    except ProjectError as e:
269 269
        messages.error(request, e)
270 270

  
271 271

  
......
292 292
                                        u,
293 293
                                        request_user=request.user),
294 294
                addmembers_form.valid_users)
295
        except (IOError, PermissionDenied), e:
295
        except ProjectError as e:
296 296
            messages.error(request, e)
297 297

  
298 298

  
......
475 475
        else:
476 476
            m = _(astakos_messages.USER_JOIN_REQUEST_SUBMITTED)
477 477
        messages.success(request, m)
478
    except (IOError, PermissionDenied), e:
478
    except ProjectError as e:
479 479
        messages.error(request, e)
480 480

  
481 481

  
......
504 504
        else:
505 505
            m = _(astakos_messages.USER_LEAVE_REQUEST_SUBMITTED)
506 506
        messages.success(request, m)
507
    except (IOError, PermissionDenied), e:
507
    except ProjectError as e:
508 508
        messages.error(request, e)
509 509

  
510 510

  
......
529 529
        cancel_membership(memb_id, request.user)
530 530
        m = _(astakos_messages.USER_REQUEST_CANCELLED)
531 531
        messages.success(request, m)
532
    except (IOError, PermissionDenied), e:
532
    except ProjectError as e:
533 533
        messages.error(request, e)
534 534

  
535 535

  
......
549 549
    try:
550 550
        memb_id = int(memb_id)
551 551
        m = accept_membership(memb_id, request.user)
552
    except (IOError, PermissionDenied), e:
552
    except ProjectError as e:
553 553
        messages.error(request, e)
554 554

  
555 555
    else:
......
574 574
    try:
575 575
        memb_id = int(memb_id)
576 576
        m = remove_membership(memb_id, request.user)
577
    except (IOError, PermissionDenied), e:
577
    except ProjectError as e:
578 578
        messages.error(request, e)
579 579
    else:
580 580
        email = escape(m.person.email)
......
598 598
    try:
599 599
        memb_id = int(memb_id)
600 600
        m = reject_membership(memb_id, request.user)
601
    except (IOError, PermissionDenied), e:
601
    except ProjectError as e:
602 602
        messages.error(request, e)
603 603
    else:
604 604
        email = escape(m.person.email)
b/snf-astakos-app/astakos/test/stress.py
47 47
os.environ['DJANGO_SETTINGS_MODULE'] = 'synnefo.settings'
48 48

  
49 49
from astakos.im.models import AstakosUser
50
from astakos.im.functions import get_related_project_id
50
from astakos.im.functions import get_related_project_id, ProjectError
51 51
from astakos.im import quotas
52 52
from views import submit, approve, join, leave
53 53
from snf_django.lib.db.transaction import commit_on_success_strict
54
from django.core.exceptions import PermissionDenied
55 54

  
56 55
USERS = {}
57 56
PROJECTS = {}
......
125 124
                        % (prefix, now, prec))
126 125
            app_id = submit(name, user_id, prec)
127 126
            prec = app_id
128
        except PermissionDenied as e:
127
        except ProjectError as e:
129 128
            logger.info('Limit reached')
130 129
        except Exception as e:
131 130
            logger.exception(e)
......
167 166
            logger.info('%s%s: user %s joining project %s'
168 167
                        % (prefix, now, user_id, proj_id))
169 168
            join(proj_id, user_id)
170
        except PermissionDenied as e:
169
        except ProjectError as e:
171 170
            logger.info('Membership already exists')
172 171
        except Exception as e:
173 172
            logger.exception(e)
......
177 176
            logger.info('%s%s: user %s leaving project %s'
178 177
                        % (prefix, now, user_id, proj_id))
179 178
            leave(proj_id, user_id)
180
        except IOError as e:
179
        except ProjectError as e:
181 180
            logger.info('No such membership')
182 181
        except Exception as e:
183 182
            logger.exception(e)
b/snf-astakos-app/astakos/test/views.py
33 33

  
34 34
from datetime import datetime, timedelta
35 35

  
36
from django.core.exceptions import PermissionDenied
37 36
from astakos.im.models import AstakosUser, ProjectApplication
38 37
from astakos.im.functions import (join_project, leave_project,
39 38
                                  submit_application, approve_application,
40
                                  get_user_by_id, check_pending_app_quota)
39
                                  get_user_by_id, check_pending_app_quota,
40
                                  ProjectForbidden)
41 41
from snf_django.lib.db.transaction import commit_on_success_strict
42 42

  
43 43

  
......
64 64

  
65 65
    ok, limit = check_pending_app_quota(owner, precursor=precursor)
66 66
    if not ok:
67
        raise PermissionDenied('Limit %s reached', limit)
67
        raise ProjectForbidden('Limit %s reached', limit)
68 68

  
69 69
    resource_policies = [('cyclades.network.private', 5)]
70 70
    data = {'owner': owner,

Also available in: Unified diff