Revision ff67242a
b/snf-astakos-app/astakos/im/forms.py | ||
---|---|---|
67 | 67 |
PROJECT_MEMBER_LEAVE_POLICIES, EMAILCHANGE_ENABLED) |
68 | 68 |
from astakos.im.widgets import DummyWidget, RecaptchaWidget |
69 | 69 |
from astakos.im.functions import ( |
70 |
send_change_email, submit_application, do_accept_membership_checks)
|
|
70 |
send_change_email, submit_application, accept_membership_checks) |
|
71 | 71 |
|
72 | 72 |
from astakos.im.util import reserved_email, reserved_verified_email, \ |
73 | 73 |
get_query, model_to_dict |
... | ... | |
877 | 877 |
help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP), required=True) |
878 | 878 |
|
879 | 879 |
def __init__(self, *args, **kwargs): |
880 |
application_id = kwargs.pop('application_id', None)
|
|
881 |
if application_id:
|
|
882 |
self.project = Project.objects.get(application__id=application_id)
|
|
880 |
chain_id = kwargs.pop('chain_id', None)
|
|
881 |
if chain_id:
|
|
882 |
self.project = Project.objects.get(id=chain_id)
|
|
883 | 883 |
self.request_user = kwargs.pop('request_user', None) |
884 | 884 |
super(AddProjectMembersForm, self).__init__(*args, **kwargs) |
885 | 885 |
|
886 | 886 |
def clean(self): |
887 | 887 |
try: |
888 |
do_accept_membership_checks(self.project, self.request_user)
|
|
888 |
accept_membership_checks(self.project, self.request_user) |
|
889 | 889 |
except PermissionDenied, e: |
890 | 890 |
raise forms.ValidationError(e) |
891 | 891 |
|
b/snf-astakos-app/astakos/im/functions.py | ||
---|---|---|
46 | 46 |
from django.contrib.auth.models import AnonymousUser |
47 | 47 |
from django.core.exceptions import PermissionDenied |
48 | 48 |
from django.db import IntegrityError |
49 |
from django.http import Http404 |
|
49 | 50 |
|
50 | 51 |
from urllib import quote |
51 | 52 |
from urlparse import urljoin |
... | ... | |
494 | 495 |
raise PermissionDenied( |
495 | 496 |
_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__) |
496 | 497 |
|
497 |
def accept_membership(project_application_id, user, request_user=None): |
|
498 |
""" |
|
499 |
Raises: |
|
500 |
django.core.exceptions.PermissionDenied |
|
501 |
IOError |
|
502 |
""" |
|
503 |
project_id = get_project_id_of_application_id(project_application_id) |
|
504 |
return do_accept_membership(project_id, user, request_user) |
|
505 |
|
|
506 |
def do_accept_membership_checks(project, request_user): |
|
498 |
def accept_membership_checks(project, request_user): |
|
507 | 499 |
checkAllowed(project, request_user) |
508 | 500 |
checkAlive(project) |
509 | 501 |
|
... | ... | |
514 | 506 |
if project.violates_members_limit(adding=1): |
515 | 507 |
raise PermissionDenied(_(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED)) |
516 | 508 |
|
517 |
def do_accept_membership(project_id, user, request_user=None):
|
|
509 |
def accept_membership(project_id, user, request_user=None): |
|
518 | 510 |
project = get_project_for_update(project_id) |
519 |
do_accept_membership_checks(project, request_user)
|
|
511 |
accept_membership_checks(project, request_user) |
|
520 | 512 |
|
521 | 513 |
membership = get_membership_for_update(project, user) |
522 | 514 |
if not membership.can_accept(): |
... | ... | |
530 | 522 |
|
531 | 523 |
return membership |
532 | 524 |
|
533 |
def reject_membership(project_application_id, user, request_user=None): |
|
534 |
""" |
|
535 |
Raises: |
|
536 |
django.core.exceptions.PermissionDenied |
|
537 |
IOError |
|
538 |
""" |
|
539 |
project_id = get_project_id_of_application_id(project_application_id) |
|
540 |
return do_reject_membership(project_id, user, request_user) |
|
541 |
|
|
542 |
def do_reject_membership_checks(project, request_user): |
|
525 |
def reject_membership_checks(project, request_user): |
|
543 | 526 |
checkAllowed(project, request_user) |
544 | 527 |
checkAlive(project) |
545 | 528 |
|
546 |
def do_reject_membership(project_id, user, request_user=None):
|
|
529 |
def reject_membership(project_id, user, request_user=None): |
|
547 | 530 |
project = get_project_for_update(project_id) |
548 |
do_reject_membership_checks(project, request_user)
|
|
531 |
reject_membership_checks(project, request_user) |
|
549 | 532 |
membership = get_membership_for_update(project, user) |
550 | 533 |
if not membership.can_reject(): |
551 | 534 |
m = _(astakos_messages.NOT_MEMBERSHIP_REQUEST) |
... | ... | |
557 | 540 |
|
558 | 541 |
return membership |
559 | 542 |
|
560 |
def remove_membership(project_application_id, user, request_user=None): |
|
561 |
""" |
|
562 |
Raises: |
|
563 |
django.core.exceptions.PermissionDenied |
|
564 |
IOError |
|
565 |
""" |
|
566 |
project_id = get_project_id_of_application_id(project_application_id) |
|
567 |
return do_remove_membership(project_id, user, request_user) |
|
568 |
|
|
569 |
def do_remove_membership_checks(project, request_user=None): |
|
543 |
def remove_membership_checks(project, request_user=None): |
|
570 | 544 |
checkAllowed(project, request_user) |
571 | 545 |
checkAlive(project) |
572 | 546 |
|
... | ... | |
574 | 548 |
if leave_policy == CLOSED_POLICY: |
575 | 549 |
raise PermissionDenied(_(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)) |
576 | 550 |
|
577 |
def do_remove_membership(project_id, user, request_user=None):
|
|
551 |
def remove_membership(project_id, user, request_user=None): |
|
578 | 552 |
project = get_project_for_update(project_id) |
579 |
do_remove_membership_checks(project, request_user)
|
|
553 |
remove_membership_checks(project, request_user) |
|
580 | 554 |
membership = get_membership_for_update(project, user) |
581 | 555 |
if not membership.can_remove(): |
582 | 556 |
m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP) |
... | ... | |
589 | 563 |
|
590 | 564 |
return membership |
591 | 565 |
|
592 |
def enroll_member(project_application_id, user, request_user=None): |
|
593 |
project_id = get_project_id_of_application_id(project_application_id) |
|
594 |
return do_enroll_member(project_id, user, request_user) |
|
595 |
|
|
596 |
def do_enroll_member(project_id, user, request_user=None): |
|
566 |
def enroll_member(project_id, user, request_user=None): |
|
597 | 567 |
project = get_project_for_update(project_id) |
598 |
do_accept_membership_checks(project, request_user)
|
|
568 |
accept_membership_checks(project, request_user) |
|
599 | 569 |
membership = create_membership(project_id, user) |
600 | 570 |
|
601 | 571 |
if not membership.can_accept(): |
... | ... | |
608 | 578 |
# TODO send proper notification |
609 | 579 |
return membership |
610 | 580 |
|
611 |
def leave_project(project_application_id, user_id): |
|
612 |
""" |
|
613 |
Raises: |
|
614 |
django.core.exceptions.PermissionDenied |
|
615 |
IOError |
|
616 |
""" |
|
617 |
project_id = get_project_id_of_application_id(project_application_id) |
|
618 |
return do_leave_project(project_id, user_id) |
|
619 |
|
|
620 |
def do_leave_project_checks(project): |
|
581 |
def leave_project_checks(project): |
|
621 | 582 |
checkAlive(project) |
622 | 583 |
|
623 | 584 |
leave_policy = project.application.member_leave_policy |
624 | 585 |
if leave_policy == CLOSED_POLICY: |
625 | 586 |
raise PermissionDenied(_(astakos_messages.MEMBER_LEAVE_POLICY_CLOSED)) |
626 | 587 |
|
627 |
def do_leave_project(project_id, user_id):
|
|
588 |
def leave_project(project_id, user_id): |
|
628 | 589 |
project = get_project_for_update(project_id) |
629 |
do_leave_project_checks(project)
|
|
590 |
leave_project_checks(project) |
|
630 | 591 |
membership = get_membership_for_update(project, user_id) |
631 | 592 |
if not membership.can_leave(): |
632 | 593 |
m = _(astakos_messages.NOT_ACCEPTED_MEMBERSHIP) |
... | ... | |
641 | 602 |
membership.save() |
642 | 603 |
return membership |
643 | 604 |
|
644 |
def join_project(project_application_id, user_id): |
|
645 |
""" |
|
646 |
Raises: |
|
647 |
django.core.exceptions.PermissionDenied |
|
648 |
IOError |
|
649 |
""" |
|
650 |
project_id = get_project_id_of_application_id(project_application_id) |
|
651 |
return do_join_project(project_id, user_id) |
|
652 |
|
|
653 |
def do_join_project_checks(project): |
|
605 |
def join_project_checks(project): |
|
654 | 606 |
checkAlive(project) |
655 | 607 |
|
656 | 608 |
join_policy = project.application.member_join_policy |
657 | 609 |
if join_policy == CLOSED_POLICY: |
658 | 610 |
raise PermissionDenied(_(astakos_messages.MEMBER_JOIN_POLICY_CLOSED)) |
659 | 611 |
|
660 |
def do_join_project(project_id, user_id):
|
|
612 |
def join_project(project_id, user_id): |
|
661 | 613 |
project = get_project_for_update(project_id) |
662 |
do_join_project_checks(project)
|
|
614 |
join_project_checks(project) |
|
663 | 615 |
membership = create_membership(project, user_id) |
664 | 616 |
|
665 | 617 |
join_policy = project.application.member_join_policy |
... | ... | |
778 | 730 |
|
779 | 731 |
project.resume() |
780 | 732 |
sync_projects() |
733 |
|
|
734 |
def get_by_chain_or_404(chain_id): |
|
735 |
try: |
|
736 |
project = Project.objects.get(id=chain_id) |
|
737 |
application = project.application |
|
738 |
return project, application |
|
739 |
except: |
|
740 |
application = ProjectApplication.objects.latest_of_chain(chain_id) |
|
741 |
if application is None: |
|
742 |
raise Http404 |
|
743 |
else: |
|
744 |
return None, application |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
1249 | 1249 |
q = q | Q(name__icontains=s) |
1250 | 1250 |
return self.filter(q) |
1251 | 1251 |
|
1252 |
def latest_of_chain(self, chain_id): |
|
1253 |
try: |
|
1254 |
return self.filter(chain=chain_id).order_by('-id')[0] |
|
1255 |
except IndexError: |
|
1256 |
return None |
|
1252 | 1257 |
|
1253 | 1258 |
USER_STATUS_DISPLAY = { |
1254 | 1259 |
0: _('Join requested'), |
b/snf-astakos-app/astakos/im/tables.py | ||
---|---|---|
44 | 44 |
|
45 | 45 |
from astakos.im.models import * |
46 | 46 |
from astakos.im.templatetags.filters import truncatename |
47 |
from astakos.im.functions import do_join_project_checks, \
|
|
48 |
do_leave_project_checks
|
|
47 |
from astakos.im.functions import join_project_checks, \ |
|
48 |
leave_project_checks |
|
49 | 49 |
|
50 | 50 |
DEFAULT_DATE_FORMAT = "d/m/Y" |
51 | 51 |
|
... | ... | |
190 | 190 |
|
191 | 191 |
if project: |
192 | 192 |
try: |
193 |
do_join_project_checks(project)
|
|
193 |
join_project_checks(project) |
|
194 | 194 |
can_join = True |
195 | 195 |
except PermissionDenied, e: |
196 | 196 |
pass |
197 | 197 |
|
198 | 198 |
try: |
199 |
do_leave_project_checks(project)
|
|
199 |
leave_project_checks(project) |
|
200 | 200 |
can_leave = True |
201 | 201 |
except PermissionDenied: |
202 | 202 |
pass |
b/snf-astakos-app/astakos/im/urls.py | ||
---|---|---|
62 | 62 |
url(r'^projects/update/(?P<application_id>\d+)/?$', 'project_update', {}, name='project_update'), |
63 | 63 |
url(r'^projects/?$', 'project_list', {}, name='project_list'), |
64 | 64 |
url(r'^projects/search/?$', 'project_search', {}, name='project_search'), |
65 |
url(r'^projects/(?P<application_id>\d+)/?$', 'project_detail', {}, name='project_detail'),
|
|
66 |
url(r'^projects/(?P<application_id>\d+)/join/?$', 'project_join', {}, name='project_join'),
|
|
67 |
url(r'^projects/(?P<application_id>\d+)/leave/?$', 'project_leave', {}, name='project_leave'),
|
|
68 |
url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/accept/?$', 'project_accept_member', {}, name='project_accept_member'),
|
|
69 |
url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/reject/?$', 'project_reject_member', {}, name='project_reject_member'),
|
|
70 |
url(r'^projects/(?P<application_id>\d+)/(?P<user_id>\d+)/remove/?$', 'project_remove_member', {}, name='project_remove_member'),
|
|
65 |
url(r'^projects/(?P<chain_id>\d+)/?$', 'project_detail', {}, name='project_detail'),
|
|
66 |
url(r'^projects/(?P<chain_id>\d+)/join/?$', 'project_join', {}, name='project_join'),
|
|
67 |
url(r'^projects/(?P<chain_id>\d+)/leave/?$', 'project_leave', {}, name='project_leave'),
|
|
68 |
url(r'^projects/(?P<chain_id>\d+)/(?P<user_id>\d+)/accept/?$', 'project_accept_member', {}, name='project_accept_member'),
|
|
69 |
url(r'^projects/(?P<chain_id>\d+)/(?P<user_id>\d+)/reject/?$', 'project_reject_member', {}, name='project_reject_member'),
|
|
70 |
url(r'^projects/(?P<chain_id>\d+)/(?P<user_id>\d+)/remove/?$', 'project_remove_member', {}, name='project_remove_member'),
|
|
71 | 71 |
|
72 | 72 |
url(r'^projects/how_it_works/?$', 'how_it_works', {}, name='how_it_works'), |
73 | 73 |
url(r'^remove_auth_provider/(?P<pk>\d+)?$', 'remove_auth_provider', {}, name='remove_auth_provider'), |
b/snf-astakos-app/astakos/im/views.py | ||
---|---|---|
96 | 96 |
send_activation as send_activation_func, |
97 | 97 |
SendNotificationError, |
98 | 98 |
accept_membership, reject_membership, remove_membership, |
99 |
leave_project, join_project, enroll_member) |
|
99 |
leave_project, join_project, enroll_member, |
|
100 |
get_by_chain_or_404) |
|
100 | 101 |
from astakos.im.settings import ( |
101 | 102 |
COOKIE_DOMAIN, LOGOUT_NEXT, |
102 | 103 |
LOGGING_LEVEL, PAGINATE_BY, |
... | ... | |
1132 | 1133 |
@signed_terms_required |
1133 | 1134 |
@login_required |
1134 | 1135 |
@transaction.commit_on_success |
1135 |
def project_detail(request, application_id):
|
|
1136 |
def project_detail(request, chain_id):
|
|
1136 | 1137 |
addmembers_form = AddProjectMembersForm() |
1137 | 1138 |
if request.method == 'POST': |
1138 | 1139 |
addmembers_form = AddProjectMembersForm( |
1139 | 1140 |
request.POST, |
1140 |
application_id=int(application_id),
|
|
1141 |
chain_id=int(chain_id),
|
|
1141 | 1142 |
request_user=request.user) |
1142 | 1143 |
if addmembers_form.is_valid(): |
1143 | 1144 |
try: |
1144 | 1145 |
rollback = False |
1145 |
application_id = int(application_id)
|
|
1146 |
chain_id = int(chain_id)
|
|
1146 | 1147 |
map(lambda u: enroll_member( |
1147 |
application_id,
|
|
1148 |
chain_id,
|
|
1148 | 1149 |
u, |
1149 | 1150 |
request_user=request.user), |
1150 | 1151 |
addmembers_form.valid_users) |
... | ... | |
1162 | 1163 |
|
1163 | 1164 |
rollback = False |
1164 | 1165 |
|
1165 |
application = get_object_or_404(ProjectApplication, pk=application_id)
|
|
1166 |
try:
|
|
1167 |
members = application.project.projectmembership_set.select_related()
|
|
1168 |
except Project.DoesNotExist:
|
|
1166 |
project, application = get_by_chain_or_404(chain_id)
|
|
1167 |
if project:
|
|
1168 |
members = project.projectmembership_set.select_related() |
|
1169 |
else:
|
|
1169 | 1170 |
members = ProjectMembership.objects.none() |
1170 | 1171 |
|
1171 | 1172 |
members_table = tables.ProjectApplicationMembersTable(application, |
... | ... | |
1186 | 1187 |
return object_detail( |
1187 | 1188 |
request, |
1188 | 1189 |
queryset=ProjectApplication.objects.select_related(), |
1189 |
object_id=application_id,
|
|
1190 |
object_id=application.id,
|
|
1190 | 1191 |
template_name='im/projects/project_detail.html', |
1191 | 1192 |
extra_context={ |
1192 | 1193 |
'addmembers_form':addmembers_form, |
... | ... | |
1239 | 1240 |
@signed_terms_required |
1240 | 1241 |
@login_required |
1241 | 1242 |
@transaction.commit_manually |
1242 |
def project_join(request, application_id):
|
|
1243 |
def project_join(request, chain_id):
|
|
1243 | 1244 |
next = request.GET.get('next') |
1244 | 1245 |
if not next: |
1245 | 1246 |
next = reverse('astakos.im.views.project_detail', |
1246 |
args=(application_id,))
|
|
1247 |
args=(chain_id,))
|
|
1247 | 1248 |
|
1248 | 1249 |
rollback = False |
1249 | 1250 |
try: |
1250 |
application_id = int(application_id)
|
|
1251 |
join_project(application_id, request.user)
|
|
1251 |
chain_id = int(chain_id)
|
|
1252 |
join_project(chain_id, request.user)
|
|
1252 | 1253 |
# TODO: distinct messages for request/auto accept ??? |
1253 | 1254 |
messages.success(request, _(astakos_messages.USER_JOIN_REQUEST_SUBMITED)) |
1254 | 1255 |
except (IOError, PermissionDenied), e: |
... | ... | |
1269 | 1270 |
@signed_terms_required |
1270 | 1271 |
@login_required |
1271 | 1272 |
@transaction.commit_manually |
1272 |
def project_leave(request, application_id):
|
|
1273 |
def project_leave(request, chain_id):
|
|
1273 | 1274 |
next = request.GET.get('next') |
1274 | 1275 |
if not next: |
1275 | 1276 |
next = reverse('astakos.im.views.project_list') |
1276 | 1277 |
|
1277 | 1278 |
rollback = False |
1278 | 1279 |
try: |
1279 |
application_id = int(application_id)
|
|
1280 |
leave_project(application_id, request.user)
|
|
1280 |
chain_id = int(chain_id)
|
|
1281 |
leave_project(chain_id, request.user)
|
|
1281 | 1282 |
except (IOError, PermissionDenied), e: |
1282 | 1283 |
messages.error(request, e) |
1283 | 1284 |
except BaseException, e: |
... | ... | |
1297 | 1298 |
@signed_terms_required |
1298 | 1299 |
@login_required |
1299 | 1300 |
@transaction.commit_manually |
1300 |
def project_accept_member(request, application_id, user_id):
|
|
1301 |
def project_accept_member(request, chain_id, user_id):
|
|
1301 | 1302 |
rollback = False |
1302 | 1303 |
try: |
1303 |
application_id = int(application_id)
|
|
1304 |
chain_id = int(chain_id)
|
|
1304 | 1305 |
user_id = int(user_id) |
1305 |
m = accept_membership(application_id, user_id, request.user)
|
|
1306 |
m = accept_membership(chain_id, user_id, request.user)
|
|
1306 | 1307 |
except (IOError, PermissionDenied), e: |
1307 | 1308 |
messages.error(request, e) |
1308 | 1309 |
except BaseException, e: |
... | ... | |
1318 | 1319 |
transaction.rollback() |
1319 | 1320 |
else: |
1320 | 1321 |
transaction.commit() |
1321 |
return redirect(reverse('project_detail', args=(application_id,)))
|
|
1322 |
return redirect(reverse('project_detail', args=(chain_id,)))
|
|
1322 | 1323 |
|
1323 | 1324 |
@require_http_methods(["POST"]) |
1324 | 1325 |
@signed_terms_required |
1325 | 1326 |
@login_required |
1326 | 1327 |
@transaction.commit_manually |
1327 |
def project_remove_member(request, application_id, user_id):
|
|
1328 |
def project_remove_member(request, chain_id, user_id):
|
|
1328 | 1329 |
rollback = False |
1329 | 1330 |
try: |
1330 |
application_id = int(application_id)
|
|
1331 |
chain_id = int(chain_id)
|
|
1331 | 1332 |
user_id = int(user_id) |
1332 |
m = remove_membership(application_id, user_id, request.user)
|
|
1333 |
m = remove_membership(chain_id, user_id, request.user)
|
|
1333 | 1334 |
except (IOError, PermissionDenied), e: |
1334 | 1335 |
messages.error(request, e) |
1335 | 1336 |
except BaseException, e: |
... | ... | |
1345 | 1346 |
transaction.rollback() |
1346 | 1347 |
else: |
1347 | 1348 |
transaction.commit() |
1348 |
return redirect(reverse('project_detail', args=(application_id,)))
|
|
1349 |
return redirect(reverse('project_detail', args=(chain_id,)))
|
|
1349 | 1350 |
|
1350 | 1351 |
@require_http_methods(["POST"]) |
1351 | 1352 |
@signed_terms_required |
1352 | 1353 |
@login_required |
1353 | 1354 |
@transaction.commit_manually |
1354 |
def project_reject_member(request, application_id, user_id):
|
|
1355 |
def project_reject_member(request, chain_id, user_id):
|
|
1355 | 1356 |
rollback = False |
1356 | 1357 |
try: |
1357 |
application_id = int(application_id)
|
|
1358 |
chain_id = int(chain_id)
|
|
1358 | 1359 |
user_id = int(user_id) |
1359 |
m = reject_membership(application_id, user_id, request.user)
|
|
1360 |
m = reject_membership(chain_id, user_id, request.user)
|
|
1360 | 1361 |
except (IOError, PermissionDenied), e: |
1361 | 1362 |
messages.error(request, e) |
1362 | 1363 |
except BaseException, e: |
... | ... | |
1372 | 1373 |
transaction.rollback() |
1373 | 1374 |
else: |
1374 | 1375 |
transaction.commit() |
1375 |
return redirect(reverse('project_detail', args=(application_id,)))
|
|
1376 |
return redirect(reverse('project_detail', args=(chain_id,)))
|
|
1376 | 1377 |
|
1377 | 1378 |
def landing(request): |
1378 | 1379 |
return render_response( |
1379 | 1380 |
'im/landing.html', |
1380 |
context_instance=get_context(request)) |
|
1381 |
context_instance=get_context(request)) |
Also available in: Unified diff