Skip to content

Commit e23ac26

Browse files
committed
Refactor permission
1 parent 7bc3488 commit e23ac26

File tree

5 files changed

+212
-75
lines changed

5 files changed

+212
-75
lines changed

dref/models.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,44 @@ def save(self, *args, **kwargs):
662662
def __str__(self):
663663
return f'{self.title}{self.created_at.date()}, {self.get_status_display()}'
664664

665+
@staticmethod
666+
def get_for(user):
667+
user_id = user.id
668+
print(Dref.objects.annotate(
669+
created_user_list=models.F('created_by'),
670+
users_list=models.F('users'),
671+
op_users=models.Subquery(
672+
DrefOperationalUpdate.objects.filter(
673+
dref=models.OuterRef('id')
674+
).order_by().values('id').annotate(
675+
c=models.F('users')
676+
).values('c')[:1]
677+
),
678+
).values("created_user_list", "users_list", "op_users"))
679+
return Dref.objects.annotate(
680+
created_user_list=models.F('created_by'),
681+
users_list=models.F('users'),
682+
op_users=models.Subquery(
683+
DrefOperationalUpdate.objects.filter(
684+
dref=models.OuterRef('id')
685+
).order_by().values('id').annotate(
686+
c=models.F('users')
687+
).values('c')[:1]
688+
),
689+
fr_users=models.Subquery(
690+
DrefFinalReport.objects.filter(
691+
dref=models.OuterRef('id')
692+
).order_by().values('id').annotate(
693+
c=models.F('users')
694+
).values('c')[:1],
695+
)
696+
).filter(
697+
models.Q(created_user_list=user_id) |
698+
models.Q(users_list=user_id) |
699+
models.Q(op_users=user_id) |
700+
models.Q(fr_users=user_id)
701+
).distinct()
702+
665703

666704
class DrefFile(models.Model):
667705
file = models.FileField(
@@ -1175,6 +1213,25 @@ class Meta:
11751213
verbose_name = _('Dref Operational Update')
11761214
verbose_name_plural = _('Dref Operational Updates')
11771215

1216+
@staticmethod
1217+
def get_for(user):
1218+
user_id = user.id
1219+
return DrefOperationalUpdate.objects.annotate(
1220+
created_user_list=models.F('created_by'),
1221+
users_list=models.F('users'),
1222+
dref_users=models.Subquery(
1223+
Dref.objects.filter(
1224+
drefoperationalupdate=models.OuterRef('id')
1225+
).order_by().values('drefoperationalupdate').annotate(
1226+
c=models.F('users')
1227+
).values('c')[:1]
1228+
)
1229+
).filter(
1230+
models.Q(created_user_list=user_id) |
1231+
models.Q(users_list=user_id) |
1232+
models.Q(dref_users=user_id)
1233+
).distinct()
1234+
11781235

11791236
class DrefFinalReport(models.Model):
11801237
created_at = models.DateTimeField(verbose_name=_('created at'), auto_now_add=True)

dref/permissions.py

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Dref,
77
DrefOperationalUpdate,
88
)
9+
from dref.utils import get_users_in_dref, get_users_in_dref_operational_update
910

1011

1112
class IsSuperAdmin(permissions.BasePermission):
@@ -18,50 +19,16 @@ def has_object_permission(self, request, view, obj):
1819
return request.user.is_superuser
1920

2021

21-
class DrefViewUpdatePermission(IsSuperAdmin):
22-
message = "Can view and update Dref"
23-
24-
def has_permission(self, request, view):
25-
if request.method == "POST":
26-
return True
27-
return True
28-
29-
def has_object_permission(self, request, view, obj):
30-
user = request.user
31-
if user.is_superuser:
32-
return True
33-
if request.method in ["PUT", "DELETE", "PATCH"]:
34-
return Dref.objects.filter(
35-
models.Q(id=obj.id, users=user) |
36-
models.Q(id=obj.id, created_by=user)
37-
).exists()
38-
return True
22+
class DrefViewUpdatePermission(permissions.BasePermission):
23+
message = "Can't view and update Dref"
24+
pass
3925

4026

4127
class DrefOperationalUpdateCreatePermission(permissions.BasePermission):
4228
message = "Can create Operational Update for whom dref is shared with"
4329

4430
def has_permission(self, request, view):
45-
user = request.user
46-
dref = request.data.get('dref')
47-
if request.method == "POST":
48-
if user.is_superuser:
49-
return True
50-
if dref:
51-
return Dref.objects.filter(
52-
models.Q(id=dref, users=user) |
53-
models.Q(id=dref, created_by=user),
54-
is_published=True
55-
).exists()
56-
return True
31+
pass
5732

5833
def has_object_permission(self, request, view, obj):
59-
user = request.user
60-
if user.is_superuser:
61-
return True
62-
if request.method in ["PUT", "DELETE", "PATCH"]:
63-
return DrefOperationalUpdate.objects.filter(
64-
models.Q(id=obj.id, users=user) |
65-
models.Q(id=obj.id, created_by=user)
66-
).exists()
67-
return True
34+
pass

dref/test_views.py

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ def test_final_report_update_once_published(self):
746746
# try to publish this report
747747
url = f'/api/v2/dref-final-report/{final_report.id}/publish/'
748748
data = {}
749-
self.client.force_authenticate(self.user)
749+
self.client.force_authenticate(user1)
750750
response = self.client.post(url, data)
751751
self.assert_200(response)
752752
self.assertEqual(response.data['is_published'], True)
@@ -986,6 +986,7 @@ def test_optimistic_lock_in_final_report(self):
986986
data['modified_at'] = datetime.now() + timedelta(days=2)
987987
response = self.client.patch(url, data=data)
988988
self.assert_200(response)
989+
989990
def test_dref_permission(self):
990991
user1 = UserFactory.create(
991992
username='[email protected]',
@@ -1063,7 +1064,7 @@ def test_dref_permission(self):
10631064
self.assertEqual(response.status_code, 200)
10641065
self.assertEqual(len(response.data['results']), 0)
10651066

1066-
def test_dref_operational_update_permission(self):
1067+
def test_superuser_permisssion_operational_update(self):
10671068
super_user = UserFactory.create(
10681069
username='[email protected]',
10691070
first_name='Test',
@@ -1072,56 +1073,105 @@ def test_dref_operational_update_permission(self):
10721073
10731074
is_superuser=True,
10741075
)
1075-
user1, user2 = UserFactory.create_batch(2)
10761076
dref = DrefFactory.create(
10771077
title='Test Title',
10781078
is_published=True,
10791079
)
1080-
dref.users.add(user1)
10811080
self.country1 = Country.objects.create(name='abc')
10821081
self.district1 = District.objects.create(name='test district1', country=self.country1)
1083-
old_op_count = DrefOperationalUpdate.objects.filter(dref=dref).count()
10841082
url = '/api/v2/dref-op-update/'
10851083
data = {
10861084
'dref': dref.id,
10871085
'country': self.country1.id,
10881086
'district': [self.district1.id],
10891087
}
1090-
# authenticate with user for whom dref is not shared
1091-
self.authenticate(self.user)
1092-
response = self.client.post(url, data=data)
1093-
self.assert_403(response)
1094-
# authenticate with user for whom dref is shared
1095-
self.authenticate(user1)
1088+
# authenticate with superuser
1089+
self.authenticate(super_user)
10961090
response = self.client.post(url, data=data)
10971091
self.assert_201(response)
1098-
self.assertEqual(
1099-
DrefOperationalUpdate.objects.filter(dref=dref).count(),
1100-
old_op_count + 1
1101-
)
11021092

1103-
def test_superuser_permisssion_operational_update(self):
1104-
super_user = UserFactory.create(
1105-
username='[email protected]',
1106-
first_name='Test',
1107-
last_name='User1',
1108-
password='admin123',
1109-
1110-
is_superuser=True,
1093+
def test_operational_update_view_permission(self):
1094+
Dref.objects.all().delete()
1095+
user1, user2, user3 = UserFactory.create_batch(3)
1096+
dref = DrefFactory.create(
1097+
title='Test Title',
1098+
is_published=True,
1099+
created_by=user1
11111100
)
1101+
operational_update = DrefOperationalUpdateFactory.create(
1102+
dref=dref,
1103+
)
1104+
operational_update.users.set([user3])
1105+
self.country1 = Country.objects.create(name='abc')
1106+
self.district1 = District.objects.create(name='test district1', country=self.country1)
1107+
1108+
# Here user1 is able to see the operational_update
1109+
url = '/api/v2/dref-op-update/'
1110+
self.authenticate(user1)
1111+
response = self.client.get(url)
1112+
self.assert_200(response)
1113+
1114+
# authenticate with the user3
1115+
# here user3 should be able to view dref
1116+
# since user3 is assigned to op-update created from dref
1117+
dref_url = '/api/v2/dref/'
1118+
self.authenticate(user3)
1119+
response = self.client.get(dref_url)
1120+
self.assert_200(response)
1121+
self.assertEqual(len(response.data['results']), 1)
1122+
self.assertEqual(response.data['results'][0]['id'], dref.id)
1123+
1124+
# authenticate with user2
1125+
# here user2 is not able to view dref
1126+
self.authenticate(user2)
1127+
response = self.client.get(dref_url)
1128+
self.assert_200(response)
1129+
self.assertEqual(len(response.data['results']), 0)
1130+
1131+
def test_concurrent_dref_operational_update(self):
1132+
user1, user2, user3 = UserFactory.create_batch(3)
1133+
print(f'{user1.id} {user2.id} {user3.id}')
11121134
dref = DrefFactory.create(
11131135
title='Test Title',
11141136
is_published=True,
1137+
created_by=user1
1138+
)
1139+
operational_update = DrefOperationalUpdateFactory.create(
1140+
dref=dref,
1141+
operational_update_number=1,
1142+
created_by=user3
11151143
)
1144+
operational_update.users.set([user3, user2])
11161145
self.country1 = Country.objects.create(name='abc')
11171146
self.district1 = District.objects.create(name='test district1', country=self.country1)
1147+
1148+
# Here user1 is able to see the operational_update
11181149
url = '/api/v2/dref-op-update/'
1119-
data = {
1120-
'dref': dref.id,
1121-
'country': self.country1.id,
1122-
'district': [self.district1.id],
1123-
}
1124-
# authenticate with superuser
1125-
self.authenticate(super_user)
1126-
response = self.client.post(url, data=data)
1127-
self.assert_201(response)
1150+
self.authenticate(user1)
1151+
response = self.client.get(url)
1152+
self.assert_200(response)
1153+
1154+
# create another operational update from corresponding dref
1155+
operation_update2 =DrefOperationalUpdateFactory.create(
1156+
dref=dref,
1157+
operational_update_number=2
1158+
)
1159+
operation_update2.users.set([user2])
1160+
1161+
# authenticate with user2
1162+
url = '/api/v2/dref-op-update/'
1163+
self.authenticate(user2)
1164+
response = self.client.get(url)
1165+
self.assert_200(response)
1166+
1167+
# user2 should also be able to view dref
1168+
dref_url = '/api/v2/dref/'
1169+
self.authenticate(user2)
1170+
response = self.client.get(dref_url)
1171+
self.assert_200(response)
1172+
self.assertEqual(len(response.data['results']), 1)
1173+
1174+
# authenticate with user1
1175+
self.authenticate(user1)
1176+
response = self.client.get(dref_url)
1177+
self.assert_200(response)

dref/utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
from django.conf import settings
22

3+
from dref.models import (
4+
Dref,
5+
DrefOperationalUpdate,
6+
DrefFinalReport,
7+
)
8+
from django.db import models
9+
from django.contrib.postgres.aggregates import ArrayAgg
10+
311

412
def get_email_context(instance):
513
from dref.serializers import DrefSerializer
@@ -11,3 +19,52 @@ def get_email_context(instance):
1119
'frontend_url': settings.FRONTEND_URL,
1220
}
1321
return email_context
22+
23+
24+
# get the list fo users in dref
25+
def get_users_in_dref():
26+
data = Dref.objects.values('id').annotate(created_user_list=ArrayAgg(
27+
'created_by', filter=models.Q(created_by__isnull=False))
28+
).annotate(
29+
users_list=ArrayAgg('users', filter=models.Q(users__isnull=False))
30+
).annotate(
31+
op_created_by=models.Subquery(
32+
DrefOperationalUpdate.objects.filter(
33+
dref=models.OuterRef('id')
34+
).order_by().values('id').annotate(
35+
c=ArrayAgg('created_by', filter=models.Q(created_by__isnull=False))
36+
).values('c')[:1]
37+
),
38+
op_users=models.Subquery(
39+
DrefOperationalUpdate.objects.filter(
40+
dref=models.OuterRef('id')
41+
).order_by().values('id').annotate(
42+
c=ArrayAgg('users', filter=models.Q(users__isnull=False))
43+
).values('c')[:1]
44+
)
45+
)
46+
return data
47+
48+
49+
# get the list fo users in dref
50+
def get_users_in_dref_operational_update():
51+
data = DrefOperationalUpdate.objects.values('id').annotate(
52+
created_user_list=ArrayAgg(
53+
'created_by', filter=models.Q(users__isnull=False)
54+
),
55+
users=ArrayAgg(
56+
'users', filter=models.Q(users__isnull=False)
57+
)
58+
)
59+
share_with_users = DrefOperationalUpdate.objects.values_list('users', flat=True)
60+
created_by_users = DrefOperationalUpdate.objects.values_list('created_by', flat=True)
61+
users = share_with_users.union(created_by_users)
62+
return users
63+
64+
65+
# get the list fo users in dref
66+
def get_users_in_dref_final_report():
67+
share_with_users = DrefFinalReport.objects.values_list('users', flat=True)
68+
created_by_users = DrefFinalReport.objects.values_list('created_by', flat=True)
69+
users = share_with_users.union(created_by_users)
70+
return users

0 commit comments

Comments
 (0)