Skip to content

Commit cd5c60c

Browse files
committed
Clean up permission checking in community lists, fix split in
track/untrack between personal/group lists, get rid of remove_document - Legacy-Id: 10680
1 parent 4696dad commit cd5c60c

8 files changed

Lines changed: 87 additions & 80 deletions

File tree

ietf/community/models.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from ietf.utils.mail import send_mail
1010
from ietf.doc.models import Document, DocEvent
11-
from ietf.group.models import Group, Role
11+
from ietf.group.models import Group
1212

1313
from ietf.community.rules import TYPES_OF_RULES, RuleManager
1414
from ietf.community.display import (TYPES_OF_SORT, DisplayField,
@@ -24,21 +24,6 @@ class CommunityList(models.Model):
2424
secret = models.CharField(max_length=255, null=True, blank=True)
2525
cached = models.TextField(null=True, blank=True)
2626

27-
def check_manager(self, user):
28-
if user == self.user:
29-
return True
30-
if not self.group or self.group.type.slug not in ('area', 'wg'):
31-
return False
32-
try:
33-
person = user.person
34-
except:
35-
return False
36-
if self.group.type.slug == 'area':
37-
return bool(Role.objects.filter(name__slug='ad', email__in=person.email_set.all(), group=self.group).count())
38-
elif self.group.type.slug == 'wg':
39-
return bool(Role.objects.filter(name__slug='chair', email__in=person.email_set.all(), group=self.group).count())
40-
return False
41-
4227
def long_name(self):
4328
if self.user:
4429
return 'Personal ID list of %s' % self.user.username

ietf/community/tests.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
88

99
class CommunityListTests(TestCase):
10-
def test_track_untrack_document(self):
10+
def test_track_untrack_document_for_personal_list_through_ajax(self):
1111
draft = make_test_data()
1212

13-
url = urlreverse("community_track_document", kwargs={ "name": draft.name })
13+
url = urlreverse("community_personal_track_document", kwargs={ "name": draft.name })
1414
login_testing_unauthorized(self, "plain", url)
1515

1616
# track
@@ -21,10 +21,35 @@ def test_track_untrack_document(self):
2121
self.assertEqual(list(clist.added_ids.all()), [draft])
2222

2323
# untrack
24-
url = urlreverse("community_untrack_document", kwargs={ "name": draft.name })
24+
url = urlreverse("community_personal_untrack_document", kwargs={ "name": draft.name })
2525
r = self.client.post(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
2626
self.assertEqual(r.status_code, 200)
2727
self.assertEqual(json.loads(r.content)["success"], True)
2828
clist = CommunityList.objects.get(user__username="plain")
2929
self.assertEqual(list(clist.added_ids.all()), [])
30+
31+
def test_track_untrack_document_for_group_list(self):
32+
draft = make_test_data()
33+
34+
url = urlreverse("community_group_track_document", kwargs={ "name": draft.name, "acronym": draft.group.acronym })
35+
login_testing_unauthorized(self, "marschairman", url)
36+
37+
# track
38+
r = self.client.get(url)
39+
self.assertEqual(r.status_code, 200)
40+
41+
r = self.client.post(url)
42+
self.assertEqual(r.status_code, 302)
43+
clist = CommunityList.objects.get(group__acronym=draft.group.acronym)
44+
self.assertEqual(list(clist.added_ids.all()), [draft])
45+
46+
# untrack
47+
url = urlreverse("community_group_untrack_document", kwargs={ "name": draft.name, "acronym": draft.group.acronym })
48+
r = self.client.get(url)
49+
self.assertEqual(r.status_code, 200)
50+
51+
r = self.client.post(url)
52+
self.assertEqual(r.status_code, 302)
53+
clist = CommunityList.objects.get(group__acronym=draft.group.acronym)
54+
self.assertEqual(list(clist.added_ids.all()), [])
3055

ietf/community/urls.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
url(r'^personal/(?P<secret>[a-f0-9]+)/subscribe/significant/$', 'subscribe_personal_list', {'significant': True}, name='subscribe_significant_personal_list'),
1313
url(r'^personal/(?P<secret>[a-f0-9]+)/unsubscribe/$', 'unsubscribe_personal_list', {'significant': False}, name='unsubscribe_personal_list'),
1414
url(r'^personal/(?P<secret>[a-f0-9]+)/unsubscribe/significant/$', 'unsubscribe_personal_list', {'significant': True}, name='unsubscribe_significant_personal_list'),
15+
url(r'^personal/trackdocument/(?P<name>[^/]+)/$', 'track_document', name='community_personal_track_document'),
16+
url(r'^personal/untrackdocument/(?P<name>[^/]+)/$', 'untrack_document', name='community_personal_untrack_document'),
1517

1618
url(r'^group/(?P<acronym>[\w.@+-]+)/$', 'manage_group_list', name='manage_group_list'),
1719
url(r'^group/(?P<acronym>[\w.@+-]+)/view/$', 'view_group_list', name='view_group_list'),
@@ -22,11 +24,10 @@
2224
url(r'^group/(?P<acronym>[\w.@+-]+)/subscribe/significant/$', 'subscribe_group_list', {'significant': True}, name='subscribe_significant_group_list'),
2325
url(r'^group/(?P<acronym>[\w.@+-]+)/unsubscribe/$', 'unsubscribe_group_list', {'significant': False}, name='unsubscribe_group_list'),
2426
url(r'^group/(?P<acronym>[\w.@+-]+)/unsubscribe/significant/$', 'unsubscribe_group_list', {'significant': True}, name='unsubscribe_significant_group_list'),
27+
url(r'^group/(?P<acronym>[\w.@+-]+)/trackdocument/(?P<name>[^/]+)/$', 'track_document', name='community_group_track_document'),
28+
url(r'^group/(?P<acronym>[\w.@+-]+)/untrackdocument/(?P<name>[^/]+)/$', 'untrack_document', name='community_group_untrack_document'),
2529

26-
url(r'^trackdocument/(?P<name>[^/]+)/$', 'track_document', name='community_track_document'),
27-
url(r'^untrackdocument/(?P<name>[^/]+)/$', 'untrack_document', name='community_untrack_document'),
2830

29-
url(r'^(?P<list_id>[\d]+)/remove_document/(?P<name>[^/]+)/$', 'remove_document', name='community_remove_document'),
3031
url(r'^(?P<list_id>[\d]+)/remove_rule/(?P<rule_id>[^/]+)/$', 'remove_rule', name='community_remove_rule'),
3132
url(r'^(?P<list_id>[\d]+)/subscribe/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_subscription', name='confirm_subscription'),
3233
url(r'^(?P<list_id>[\d]+)/subscribe/significant/confirm/(?P<email>[\w.@+-]+)/(?P<date>[\d]+)/(?P<confirm_hash>[a-f0-9]+)/$', 'confirm_significant_subscription', name='confirm_significant_subscription'),

ietf/community/utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from ietf.group.models import Role
2+
3+
def can_manage_community_list_for_group(user, group):
4+
if not user or not user.is_authenticated() or not group:
5+
return False
6+
7+
if group.type_id == 'area':
8+
return Role.objects.filter(name__slug='ad', person__user=user, group=group).exists()
9+
elif group.type_id in ('wg', 'rg'):
10+
return Role.objects.filter(name__slug='chair', person__user=user, group=group).exists()
11+
else:
12+
return False
13+

ietf/community/views.py

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66

77
from django.db import IntegrityError
88
from django.conf import settings
9-
from django.contrib.auth import REDIRECT_FIELD_NAME
109
from django.http import HttpResponse, HttpResponseForbidden, Http404, HttpResponseRedirect
1110
from django.shortcuts import get_object_or_404, render, redirect
12-
from django.utils.http import urlquote
1311
from django.contrib.auth.decorators import login_required
1412

1513
from ietf.community.models import CommunityList, Rule, EmailSubscription
1614
from ietf.community.forms import RuleForm, DisplayForm, SubscribeForm, UnSubscribeForm
15+
from ietf.community.utils import can_manage_community_list_for_group
1716
from ietf.group.models import Group
1817
from ietf.doc.models import DocEvent, Document
1918

@@ -48,38 +47,37 @@ def _manage_list(request, clist):
4847
'rule_form': rule_form})
4948

5049

50+
@login_required
5151
def manage_personal_list(request):
52-
user = request.user
53-
if not user.is_authenticated():
54-
path = urlquote(request.get_full_path())
55-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
56-
return HttpResponseRedirect('%s?%s=%s' % tup)
5752
clist = CommunityList.objects.get_or_create(user=request.user)[0]
58-
if not clist.check_manager(request.user):
59-
path = urlquote(request.get_full_path())
60-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
61-
return HttpResponseRedirect('%s?%s=%s' % tup)
6253
return _manage_list(request, clist)
6354

6455

56+
@login_required
6557
def manage_group_list(request, acronym):
6658
group = get_object_or_404(Group, acronym=acronym)
67-
if group.type.slug not in ('area', 'wg'):
68-
raise Http404
59+
if not can_manage_community_list_for_group(request.user, group):
60+
return HttpResponseForbidden("You do not have permission to access this view")
61+
6962
clist = CommunityList.objects.get_or_create(group=group)[0]
70-
if not clist.check_manager(request.user):
71-
path = urlquote(request.get_full_path())
72-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
73-
return HttpResponseRedirect('%s?%s=%s' % tup)
7463
return _manage_list(request, clist)
7564

7665
@login_required
77-
def track_document(request, name):
66+
def track_document(request, name, acronym=None):
7867
doc = get_object_or_404(Document, docalias__name=name)
7968

8069
if request.method == "POST":
81-
clist = CommunityList.objects.get_or_create(user=request.user)[0]
70+
if acronym:
71+
group = get_object_or_404(Group, acronym=acronym)
72+
if not can_manage_community_list_for_group(request.user, group):
73+
return HttpResponseForbidden("You do not have permission to access this view")
74+
75+
clist = CommunityList.objects.get_or_create(group=group)[0]
76+
else:
77+
clist = CommunityList.objects.get_or_create(user=request.user)[0]
78+
8279
clist.added_ids.add(doc)
80+
8381
if request.is_ajax():
8482
return HttpResponse(json.dumps({ 'success': True }), content_type='text/plain')
8583
else:
@@ -90,9 +88,15 @@ def track_document(request, name):
9088
})
9189

9290
@login_required
93-
def untrack_document(request, name):
91+
def untrack_document(request, name, acronym=None):
9492
doc = get_object_or_404(Document, docalias__name=name)
95-
clist = get_object_or_404(CommunityList, user=request.user)
93+
if acronym:
94+
group = get_object_or_404(Group, acronym=acronym)
95+
if not can_manage_community_list_for_group(request.user, group):
96+
return HttpResponseForbidden("You do not have permission to access this view")
97+
clist = get_object_or_404(CommunityList, group=group)
98+
else:
99+
clist = get_object_or_404(CommunityList, user=request.user)
96100

97101
if request.method == "POST":
98102
clist.added_ids.remove(doc)
@@ -106,23 +110,13 @@ def untrack_document(request, name):
106110
})
107111

108112
@login_required
109-
def remove_document(request, list_id, name):
113+
def remove_rule(request, list_id, rule_id):
110114
clist = get_object_or_404(CommunityList, pk=list_id)
111-
if not clist.check_manager(request.user):
112-
return HttpResponseForbidden("You do not have permission to access this view")
113-
114-
doc = get_object_or_404(Document, docalias__name=name)
115-
clist.added_ids.remove(doc)
116-
117-
return HttpResponseRedirect(clist.get_manage_url())
118115

116+
if ((clist.user and clist.user != request.user)
117+
or (clist.group and not can_manage_community_list_for_group(request.user, clist.group))):
118+
return HttpResponseForbidden("You do not have permission to access this view")
119119

120-
def remove_rule(request, list_id, rule_id):
121-
clist = get_object_or_404(CommunityList, pk=list_id)
122-
if not clist.check_manager(request.user):
123-
path = urlquote(request.get_full_path())
124-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
125-
return HttpResponseRedirect('%s?%s=%s' % tup)
126120
rule = get_object_or_404(Rule, pk=rule_id)
127121
rule.delete()
128122
return HttpResponseRedirect(clist.get_manage_url())
@@ -218,30 +212,19 @@ def _csv_list(request, clist):
218212
writer.writerow(row)
219213
return response
220214

221-
215+
@login_required
222216
def csv_personal_list(request):
223-
user = request.user
224-
if not user.is_authenticated():
225-
path = urlquote(request.get_full_path())
226-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
227-
return HttpResponseRedirect('%s?%s=%s' % tup)
228-
clist = CommunityList.objects.get_or_create(user=user)[0]
229-
if not clist.check_manager(user):
230-
path = urlquote(request.get_full_path())
231-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
232-
return HttpResponseRedirect('%s?%s=%s' % tup)
217+
clist = CommunityList.objects.get_or_create(user=request.user)[0]
233218
return _csv_list(request, clist)
234219

235220

221+
@login_required
236222
def csv_group_list(request, acronym):
237223
group = get_object_or_404(Group, acronym=acronym)
238-
if group.type.slug not in ('area', 'wg'):
239-
raise Http404
224+
if not can_manage_community_list_for_group(request.user, group):
225+
return HttpResponseForbidden("You do not have permission to access this view")
226+
240227
clist = CommunityList.objects.get_or_create(group=group)[0]
241-
if not clist.check_manager(request.user):
242-
path = urlquote(request.get_full_path())
243-
tup = settings.LOGIN_URL, REDIRECT_FIELD_NAME, path
244-
return HttpResponseRedirect('%s?%s=%s' % tup)
245228
return _csv_list(request, clist)
246229

247230
def view_csv_personal_list(request, secret):

ietf/templates/community/manage_clist.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ <h1>{{ cl.long_name }}</h1>
4747
<tr>
4848
<td>{{ doc.display_name }}</td>
4949
<td>{{ doc.get_state }}</td>
50-
<td><a href="{{ doc.get_absolute_url }}">{{ doc.title }}</a></td>
51-
<td><a class="btn btn-danger btn-xs" href="{% url "community_remove_document" cl.pk doc.pk %}">Remove</a></td>
50+
<td><a href="{{ doc.get_absolute_url }}">{{ doc.title }}</a></td>
51+
<td><a class="btn btn-danger btn-xs" href="{% if cl.user %}{% url "community_personal_untrack_document" doc.pk %}{% else %}{% url "community_group_untrack_document" %}{% endif %}">Remove</a></td>
5252
</tr>
5353
{% endfor %}
5454
</tbody>

ietf/templates/doc/document_draft.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,9 @@
435435
</div>
436436
{% if user.is_authenticated %}
437437
{% if tracking_document %}
438-
<a class="btn btn-default btn-xs community-list-add-remove-doc" href="{% url "community_untrack_document" doc.name %}" title="Remove from your personal ID list"><span class="fa fa-bookmark-o"></span> Untrack</a>
438+
<a class="btn btn-default btn-xs community-list-add-remove-doc" href="{% url "community_personal_untrack_document" doc.name %}" title="Remove from your personal ID list"><span class="fa fa-bookmark-o"></span> Untrack</a>
439439
{% else %}
440-
<a class="btn btn-default btn-xs community-list-add-remove-doc" href="{% url "community_track_document" doc.name %}" title="Add to your personal ID list"><span class="fa fa-bookmark"></span> Track</a>
440+
<a class="btn btn-default btn-xs community-list-add-remove-doc" href="{% url "community_personal_track_document" doc.name %}" title="Add to your personal ID list"><span class="fa fa-bookmark"></span> Track</a>
441441
{% endif %}
442442
{% endif %}
443443

ietf/templates/doc/search/search_result_row.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
<td>
1515
{% if user.is_authenticated %}
1616
{% if doc.name in doc_is_tracked %}
17-
<a href="{% url "community_untrack_document" doc.name %}" class="community-list-add-remove-doc" title="Remove from your personal ID list">
17+
<a href="{% url "community_personal_untrack_document" doc.name %}" class="community-list-add-remove-doc" title="Remove from your personal ID list">
1818
<span class="fa fa-bookmark"></span>
1919
</a>
2020
{% else %}
21-
<a href="{% url "community_track_document" doc.name %}" class="community-list-add-remove-doc" title="Add to your personal ID list">
21+
<a href="{% url "community_personal_track_document" doc.name %}" class="community-list-add-remove-doc" title="Add to your personal ID list">
2222
<span class="fa fa-bookmark-o"></span>
2323
</a>
2424
{% endif %}

0 commit comments

Comments
 (0)