Skip to content

Commit 1ba222c

Browse files
API: Allow filtering users on last_login/date_joined (#12640)
1 parent a18fbcd commit 1ba222c

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed

dojo/api_v2/views.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
ApiRiskAcceptanceFilter,
6161
ApiTemplateFindingFilter,
6262
ApiTestFilter,
63+
ApiUserFilter,
6364
ReportFindingFilter,
6465
ReportFindingFilterWithoutObjectLookups,
6566
TestImportAPIFilter,
@@ -2379,15 +2380,7 @@ class UsersViewSet(
23792380
serializer_class = serializers.UserSerializer
23802381
queryset = User.objects.none()
23812382
filter_backends = (DjangoFilterBackend,)
2382-
filterset_fields = [
2383-
"id",
2384-
"username",
2385-
"first_name",
2386-
"last_name",
2387-
"email",
2388-
"is_active",
2389-
"is_superuser",
2390-
]
2383+
filterset_class = ApiUserFilter
23912384
permission_classes = (permissions.UserHasConfigurationPermissionSuperuser,)
23922385

23932386
def get_queryset(self):

dojo/filters.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
Test_Import_Finding_Action,
8686
Test_Type,
8787
TextQuestion,
88+
User,
8889
Vulnerability_Id,
8990
)
9091
from dojo.product.queries import get_authorized_products
@@ -3553,6 +3554,44 @@ def filter(self, qs, value):
35533554
return self.options[value][1](self, qs, self.options[value][0])
35543555

35553556

3557+
class ApiUserFilter(filters.FilterSet):
3558+
last_login = filters.DateFromToRangeFilter()
3559+
date_joined = filters.DateFromToRangeFilter()
3560+
is_active = filters.BooleanFilter()
3561+
is_superuser = filters.BooleanFilter()
3562+
username = filters.CharFilter(lookup_expr="icontains")
3563+
first_name = filters.CharFilter(lookup_expr="icontains")
3564+
last_name = filters.CharFilter(lookup_expr="icontains")
3565+
email = filters.CharFilter(lookup_expr="icontains")
3566+
class Meta:
3567+
model = User
3568+
fields = [
3569+
"id",
3570+
"username",
3571+
"first_name",
3572+
"last_name",
3573+
"email",
3574+
"is_active",
3575+
"is_superuser",
3576+
"last_login",
3577+
"date_joined",
3578+
]
3579+
3580+
o = OrderingFilter(
3581+
# tuple-mapping retains order
3582+
fields=(
3583+
("username", "username"),
3584+
("last_name", "last_name"),
3585+
("first_name", "first_name"),
3586+
("email", "email"),
3587+
("is_active", "is_active"),
3588+
("is_superuser", "is_superuser"),
3589+
("date_joined", "date_joined"),
3590+
("last_login", "last_login"),
3591+
),
3592+
)
3593+
3594+
35563595
with warnings.catch_warnings(action="ignore", category=ManagerInheritanceWarning):
35573596
class QuestionFilter(FilterSet):
35583597
text = CharFilter(lookup_expr="icontains")

unittests/test_apiv2_user.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,41 @@ def test_user_change_password(self):
8888
}, format="json")
8989
self.assertEqual(r.status_code, 400, r.content[:1000])
9090
self.assertIn("Update of password though API is not allowed", r.content.decode("utf-8"))
91+
92+
def test_user_deactivate(self):
93+
# user with good password
94+
password = "testTEST1234!@#$"
95+
r = self.client.post(reverse("user-list"), {
96+
"username": "api-user-10",
97+
"email": "admin@dojo.com",
98+
"password": password,
99+
}, format="json")
100+
self.assertEqual(r.status_code, 201, r.content[:1000])
101+
102+
# user with good password
103+
password = "testTEST1234!@#$"
104+
r = self.client.post(reverse("user-list"), {
105+
"username": "api-user-2",
106+
"email": "admin@dojo.com",
107+
"password": password,
108+
}, format="json")
109+
self.assertEqual(r.status_code, 201, r.content[:1000])
110+
user_id = r.json()["id"]
111+
112+
# deactivate
113+
r = self.client.patch("{}{}/".format(reverse("user-list"), user_id), {
114+
"is_active": False,
115+
}, format="json")
116+
self.assertEqual(r.status_code, 200, r.content[:1000])
117+
118+
# check is_active field
119+
r = self.client.get("{}{}/".format(reverse("user-list"), user_id))
120+
self.assertEqual(r.status_code, 200, r.content[:1000])
121+
self.assertEqual(r.json()["is_active"], False, r.content[:1000])
122+
123+
# API key retrieval should fail for inactive user
124+
r = self.client.post(reverse("api-token-auth"), {
125+
"username": "api-user-2",
126+
"password": password,
127+
}, format="json")
128+
self.assertEqual(r.status_code, 400, r.content[:1000])

0 commit comments

Comments
 (0)