Skip to content

Commit 8cd5580

Browse files
#M23b. Only display the hackathons for their org or hackathons that are publicly available (#274)
* Enabling orgs * Adding tests to check for correct access * Fixing some liniting
1 parent 07d1a77 commit 8cd5580

11 files changed

Lines changed: 332 additions & 62 deletions

File tree

accounts/decorators.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from functools import wraps
22

3+
from django.shortcuts import get_object_or_404
34
from django.contrib import messages
45
from django.core.exceptions import PermissionDenied
56
from django.shortcuts import reverse, redirect
67

78
from accounts.models import UserType
9+
from hackathon.models import Hackathon, HackTeam
810

911

1012
def can_access(allowed_types, redirect_url=None, redirect_kwargs={}):
@@ -25,3 +27,51 @@ def wrapped_view(request, *args, **kwargs):
2527
return wrapped_view
2628

2729
return decorator
30+
31+
32+
def has_access_to_hackathon(redirect_url=None, redirect_kwargs={}):
33+
def decorator(view_function):
34+
@wraps(view_function)
35+
def wrapped_view(request, *args, **kwargs):
36+
if request.user.is_superuser or request.user.is_staff:
37+
return view_function(request, *args, **kwargs)
38+
39+
hackathon_id = kwargs.get('hackathon_id') or request.POST.get('hackathon-id')
40+
hackathon = get_object_or_404(Hackathon, id=hackathon_id)
41+
if (hackathon.organisation.id != 1
42+
and hackathon.organisation.id != request.user.organisation.id
43+
and hackathon.is_public is False):
44+
messages.error(request, 'You cannot access this page.')
45+
return redirect(reverse('hackathon:hackathon-list'))
46+
47+
return view_function(request, *args, **kwargs)
48+
49+
return wrapped_view
50+
51+
return decorator
52+
53+
54+
def has_access_to_team(redirect_url=None, redirect_kwargs={}):
55+
def decorator(view_function):
56+
@wraps(view_function)
57+
def wrapped_view(request, *args, **kwargs):
58+
if request.user.is_superuser or request.user.is_staff:
59+
return view_function(request, *args, **kwargs)
60+
61+
team_id = kwargs.get('team_id')
62+
team = get_object_or_404(HackTeam, id=team_id)
63+
if not team.hackathon:
64+
messages.error(request, 'You cannot access this page.')
65+
return redirect(reverse('hackathon:hackathon-list'))
66+
67+
if (team.hackathon.organisation.id != 1
68+
and team.hackathon.organisation.id != request.user.organisation.id
69+
and team.hackathon.is_public is False):
70+
messages.error(request, 'You cannot access this page.')
71+
return redirect(reverse('hackathon:hackathon-list'))
72+
73+
return view_function(request, *args, **kwargs)
74+
75+
return wrapped_view
76+
77+
return decorator

competencies/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def setUp(self):
2323

2424
self.assessment = CompetencyAssessment.objects.create(
2525
user=self.user2,
26-
is_visible=False,
26+
is_visible=True,
2727
)
2828

2929
competency_difficulty = CompetencyDifficulty.objects.create(

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ services:
3131
entrypoint: ['python3', 'manage.py', 'runserver', '0.0.0.0:8000']
3232
ports:
3333
- "8000:8000"
34+
tty: true
35+
stdin_open: true
3436

3537
mysql:
3638
image: docker.io/mysql:5.6.36

hackathon/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class Hackathon(models.Model):
7878
blank=True,
7979
help_text=("Hackathon image.")
8080
)
81-
is_public = models.BooleanField(default=False)
81+
is_public = models.BooleanField(default=True)
8282
max_participants = models.IntegerField(default=None, null=True, blank=True)
8383

8484
def __str__(self):

hackathon/templates/hackathon/hackathon_list.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<h2 class="p-orange text-center mb-4">Hackathons</h2>
1313
{% for hackathon in hackathons %}
1414
{% with authorised_types='SUPERUSER,STAFF,FACILITATOR_ADMIN,FACILITATOR_JUDGE,PARTNER_ADMIN,PARTNER_JUDGE' %}
15-
{% if hackathon.organisation.id == 1 or hackathon.organisation == user.organisation or request.user.user_type|is_types:authorised_types %}
15+
{% if hackathon.organisation.id == 1 or hackathon.organisation.id == request.user.organisation.id or request.user.user_type|is_types:authorised_types %}
1616
{% if hackathon.status != 'draft' or request.user == hackathon.created_by %}
1717
{% if not hackathon.status == 'deleted' %}
1818
{% include 'hackathon/includes/hackathon_card.html' %}

hackathon/templates/hackathon/includes/judge_team_display.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
{% endfor %}
1717
</ul>
1818
{% else %}
19-
You are currently don't have a team assigned to you.
19+
You currently don't have a team assigned to you.
2020
{% endif %}
2121
{% endwith %}
2222

hackathon/tests/test_views.py

Lines changed: 171 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.shortcuts import reverse
12
from django.test import TestCase
23
from accounts.models import CustomUser, Organisation
34
from django.utils import timezone
@@ -10,17 +11,19 @@ class TestHackathonViews(TestCase):
1011

1112
def setUp(self):
1213
"""Sets up the models for testing"""
13-
user = CustomUser.objects.create(username="testuser")
14-
staff_user = CustomUser.objects.create(username="staffuser")
15-
staff_user.is_staff = True
16-
staff_user.save()
17-
super_user = CustomUser.objects.create(username="super_user")
18-
super_user.is_staff = True
19-
super_user.is_superuser = True
20-
super_user.save()
21-
organisation = Organisation.objects.create()
22-
Hackathon.objects.create(
23-
created_by=user,
14+
organisation = Organisation.objects.create(display_name="CI")
15+
self.partner_org = Organisation.objects.create(display_name="Partner")
16+
self.user = CustomUser.objects.create(username="testuser", organisation=organisation)
17+
self.partner_user = CustomUser.objects.create(username="partnertestuser", organisation=self.partner_org)
18+
self.staff_user = CustomUser.objects.create(username="staffuser")
19+
self.staff_user.is_staff = True
20+
self.staff_user.save()
21+
self.super_user = CustomUser.objects.create(username="super_user")
22+
self.super_user.is_staff = True
23+
self.super_user.is_superuser = True
24+
self.super_user.save()
25+
self.hackathon = Hackathon.objects.create(
26+
created_by=self.user,
2427
status='published',
2528
display_name="hacktest",
2629
description="lorem ipsum",
@@ -31,8 +34,7 @@ def setUp(self):
3134
def test_render_hackathon_list(self):
3235
"""Tests the correct rendering of the hackathon list page,
3336
including contexts."""
34-
user = CustomUser.objects.get(pk=1)
35-
self.client.force_login(user)
37+
self.client.force_login(self.user)
3638
response = self.client.get('/hackathon/')
3739

3840
# Confirms the correct template, context items and queryset
@@ -48,8 +50,7 @@ def test_render_hackathon_list(self):
4850

4951
def test_update_hackathon_status(self):
5052
""" Tests that the status changes """
51-
super_user = CustomUser.objects.get(pk=3)
52-
self.client.force_login(super_user)
53+
self.client.force_login(self.super_user)
5354

5455
hackathon = Hackathon.objects.get(pk=1)
5556
status_before = hackathon.status
@@ -70,10 +71,9 @@ def test_view_hackathon(self):
7071
self.assertEqual(response.status_code, 302)
7172

7273
# Confirms the "enroll.html" template shows only for staff.
73-
user = CustomUser.objects.get(pk=1)
74-
user.is_staff = True
75-
user.save()
76-
self.client.force_login(user)
74+
self.user.is_staff = True
75+
self.user.save()
76+
self.client.force_login(self.user)
7777

7878
response = self.client.get('/hackathon/1/')
7979
self.assertTemplateUsed(response,
@@ -82,8 +82,7 @@ def test_view_hackathon(self):
8282
def test_judge_enroll_toggle(self):
8383
"""Tests that judges can correctly enroll and withdraw"""
8484

85-
user = CustomUser.objects.get(pk=1)
86-
self.client.force_login(user)
85+
self.client.force_login(self.user)
8786

8887
response = self.client.post('/hackathon/enroll/',
8988
{'hackathon-id': 1},
@@ -93,28 +92,169 @@ def test_judge_enroll_toggle(self):
9392

9493
# Confirms a non-staff user is refused
9594
self.assertEqual(response.status_code, 302)
96-
self.assertTrue(user in hackathon.participants.all())
97-
self.assertFalse(user in hackathon.judges.all())
95+
self.assertTrue(self.user in hackathon.participants.all())
96+
self.assertFalse(self.user in hackathon.judges.all())
9897

9998
# confirms staff can be enrolled as a judge
100-
staff_user = CustomUser.objects.get(pk=2)
101-
staff_user.is_staff = True
102-
staff_user.save()
103-
self.client.force_login(staff_user)
99+
self.staff_user.is_staff = True
100+
self.staff_user.save()
101+
self.client.force_login(self.staff_user)
104102

105103
response = self.client.post('/hackathon/enroll/',
106-
{'hackathon-id': 1,
104+
{'hackathon-id': self.hackathon.id,
107105
'enrollment-type': 'judge'},
108106
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
109107

110108
self.assertEqual(response.status_code, 302)
111-
self.assertTrue(staff_user in hackathon.judges.all())
109+
self.assertTrue(self.staff_user in hackathon.judges.all())
112110

113111
# Confirms staff can withdraw
114112
response = self.client.post('/hackathon/enroll/',
115-
{'hackathon-id': 1,
113+
{'hackathon-id': self.hackathon.id,
116114
'enrollment-type': 'judge'},
117115
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
118116

119117
self.assertEqual(response.status_code, 302)
120-
self.assertFalse(staff_user in hackathon.judges.all())
118+
self.assertFalse(self.staff_user in hackathon.judges.all())
119+
120+
def test_has_access_to_right_hackathons(self):
121+
hackathon = Hackathon.objects.create(
122+
created_by=self.user,
123+
status='published',
124+
display_name="hacktest",
125+
description="lorem ipsum",
126+
start_date=f'{timezone.now()}',
127+
end_date=f'{timezone.now()}',
128+
organisation=self.partner_org,
129+
is_public=False)
130+
131+
self.client.force_login(self.user)
132+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
133+
self.assertEquals(response.status_code, 302)
134+
135+
self.client.force_login(self.partner_user)
136+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
137+
self.assertEquals(response.status_code, 200)
138+
139+
self.client.force_login(self.staff_user)
140+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
141+
self.assertEquals(response.status_code, 200)
142+
143+
self.client.force_login(self.super_user)
144+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
145+
self.assertEquals(response.status_code, 200)
146+
147+
hackathon.is_public = True
148+
hackathon.save()
149+
150+
self.client.force_login(self.user)
151+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
152+
self.assertEquals(response.status_code, 200)
153+
154+
hackathon.is_public = False
155+
hackathon.save()
156+
self.user.organisation = self.partner_org
157+
self.user.save()
158+
159+
self.client.force_login(self.user)
160+
response = self.client.get(reverse('hackathon:view_hackathon', kwargs={'hackathon_id': hackathon.id}))
161+
self.assertEquals(response.status_code, 200)
162+
163+
def test_partner_enroll(self):
164+
hackathon = Hackathon.objects.create(
165+
created_by=self.user,
166+
status='published',
167+
display_name="hacktest",
168+
description="lorem ipsum",
169+
start_date=f'{timezone.now()}',
170+
end_date=f'{timezone.now()}',
171+
organisation=self.partner_org,
172+
is_public=False)
173+
174+
self.client.force_login(self.user)
175+
self.client.post('/hackathon/enroll/',
176+
{'hackathon-id': hackathon.id},
177+
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
178+
self.assertTrue(self.user not in hackathon.participants.all())
179+
180+
self.client.force_login(self.staff_user)
181+
self.client.post('/hackathon/enroll/',
182+
{'hackathon-id': hackathon.id, 'enrollment-type': 'judge'},
183+
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
184+
self.assertTrue(self.staff_user in hackathon.judges.all())
185+
186+
self.client.force_login(self.super_user)
187+
self.client.post('/hackathon/enroll/',
188+
{'hackathon-id': hackathon.id, 'enrollment-type': 'judge'},
189+
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
190+
self.assertTrue(self.super_user in hackathon.judges.all())
191+
192+
hackathon.is_public = True
193+
hackathon.save()
194+
195+
self.client.force_login(self.user)
196+
self.client.post('/hackathon/enroll/',
197+
{'hackathon-id': hackathon.id},
198+
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
199+
self.assertTrue(self.user in hackathon.participants.all())
200+
201+
hackathon.is_public = False
202+
hackathon.save()
203+
self.user.organisation = self.partner_org
204+
self.user.save()
205+
206+
# Check if it can also be removed
207+
self.client.force_login(self.user)
208+
self.client.post('/hackathon/enroll/',
209+
{'hackathon-id': hackathon.id},
210+
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
211+
self.assertTrue(self.super_user not in hackathon.participants.all())
212+
213+
def test_list_partner_hackathons(self):
214+
hackathon = Hackathon.objects.create(
215+
created_by=self.user,
216+
status='published',
217+
display_name="hacktest",
218+
description="lorem ipsum",
219+
start_date=f'{timezone.now()}',
220+
end_date=f'{timezone.now()}',
221+
organisation=self.partner_org,
222+
is_public=False)
223+
224+
# if this is more than 5, the response results will have to be paginated
225+
# because they are capped at 5
226+
num_hackathons = Hackathon.objects.count()
227+
228+
self.client.force_login(self.user)
229+
self.assertTrue(num_hackathons <= 5)
230+
response = self.client.get(reverse('hackathon:hackathon-list'))
231+
hackathons = [hackathon.id for hackathon in response.context['hackathons']]
232+
self.assertTrue(hackathon.id not in hackathons)
233+
234+
self.client.force_login(self.staff_user)
235+
response = self.client.get(reverse('hackathon:hackathon-list'))
236+
hackathons = [hackathon.id for hackathon in response.context['hackathons']]
237+
self.assertTrue(hackathon.id in hackathons)
238+
239+
self.client.force_login(self.super_user)
240+
response = self.client.get(reverse('hackathon:hackathon-list'))
241+
hackathons = [hackathon.id for hackathon in response.context['hackathons']]
242+
self.assertTrue(hackathon.id in hackathons)
243+
244+
hackathon.is_public = True
245+
hackathon.save()
246+
247+
self.client.force_login(self.user)
248+
response = self.client.get(reverse('hackathon:hackathon-list'))
249+
hackathons = [hackathon.id for hackathon in response.context['hackathons']]
250+
self.assertTrue(hackathon.id in hackathons)
251+
252+
hackathon.is_public = False
253+
hackathon.save()
254+
self.user.organisation = self.partner_org
255+
self.user.save()
256+
257+
self.client.force_login(self.user)
258+
response = self.client.get(reverse('hackathon:hackathon-list'))
259+
hackathons = [hackathon.id for hackathon in response.context['hackathons']]
260+
self.assertTrue(hackathon.id in hackathons)

0 commit comments

Comments
 (0)