Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent 400 Response for Invalid Input in Kolibri Public Content APIs #12818

Merged

Conversation

manzil-infinity180
Copy link
Contributor

@manzil-infinity180 manzil-infinity180 commented Nov 11, 2024

Summary

This pr is intended to be consistent for 400 response for retrieve function of ContentNodeTreeViewset and ImportMetadataViewset invalid input by returning a 404 response.

References

Closes: #12807

Reviewer guidance


Testing checklist

  • Contributor has fully tested the PR manually
  • If there are any front-end changes, before/after screenshots are included
  • Critical user journeys are covered by Gherkin stories
  • Critical and brittle code paths are covered by unit tests

PR process

  • PR has the correct target branch and milestone
  • PR has 'needs review' or 'work-in-progress' label
  • If PR is ready for review, a reviewer has been added. (Don't use 'Assignees')
  • If this is an important user-facing change, PR or related issue has a 'changelog' label
  • If this includes an internal dependency change, a link to the diff is provided

Reviewer checklist

  • PR is fully functional
  • PR has been tested for accessibility regressions
  • External dependency files were updated if necessary (yarn and pip)
  • Documentation is updated
  • Contributor is in AUTHORS.md

@github-actions github-actions bot added the DEV: backend Python, databases, networking, filesystem... label Nov 11, 2024
@manzil-infinity180 manzil-infinity180 changed the title changed response 404 to 400 Consistent 400 Response for Invalid Input in Kolibri Public Content APIs Nov 11, 2024
@MisRob MisRob requested review from ozer550 and jredrejo November 12, 2024 15:33
@MisRob MisRob added the TODO: needs review Waiting for review label Nov 12, 2024
jredrejo
jredrejo previously approved these changes Nov 12, 2024
Copy link
Member

@jredrejo jredrejo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally valid from my point of view, pk being None return a 400 error code, while not finding a pk should return a 404 code.
This pr solves first case.
However, tests must be fixed to pass

@jredrejo jredrejo dismissed their stale review November 12, 2024 17:09

tests are not passing

Copy link
Member

@jredrejo jredrejo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are not passing because pk is being provided, for this test to pass you either must set pk to none or change the code to return 400 when pk is not an UUID (which current code is not doing)

self = <kolibri.core.content.test.test_content_app.ContentNodeAPITestCase testMethod=test_contentnode_tree_bad_pk>

    def test_contentnode_tree_bad_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:contentnode_tree-detail",
                kwargs={"pk": "this is not a UUID"},
            )
        )
>       self.assertEqual(response.status_code, 400)
E       AssertionError: 404 != 400

@manzil-infinity180
Copy link
Contributor Author

manzil-infinity180 commented Nov 12, 2024

Tests are not passing because pk is being provided, for this test to pass you either must set pk to none or change the code to return 400 when pk is not an UUID (which current code is not doing)

self = <kolibri.core.content.test.test_content_app.ContentNodeAPITestCase testMethod=test_contentnode_tree_bad_pk>

    def test_contentnode_tree_bad_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:contentnode_tree-detail",
                kwargs={"pk": "this is not a UUID"},
            )
        )
>       self.assertEqual(response.status_code, 400)
E       AssertionError: 404 != 400

I tried with pk as None but it gives me 404 error

def test_import_metadata_bad_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:importmetadata-detail",
                kwargs={"pk": None},
            )
        )
>       self.assertEqual(response.status_code, 400)
E       AssertionError: 404 != 400
kolibri/core/content/test/test_public_api.py:105: AssertionError
----------------------------------------------------------------------------- Captured stderr setup -----------------------------------------------------------------------------
ERROR    2024-11-13 01:19:35,987 No tree cache found for 3 levels and 5 children per level
------------------------------------------------------------------------------ Captured log setup -------------------------------------------------------------------------------
ERROR    kolibri.core.content.test.test_channel_upgrade:test_channel_upgrade.py:110 No tree cache found for 3 levels and 5 children per level
----------------------------------------------------------------------------- Captured stdout call ------------------------------------------------------------------------------
INFO     2024-11-13 01:19:36,823 127.0.0.1 - - "GET /api/public/v2/importmetadata/None/" 404 0 "" "unknown"
WARNING  2024-11-13 01:19:36,824 Not Found: /api/public/v2/importmetadata/None/
------------------------------------------------------------------------------- Captured log call -------------------------------------------------------------------------------
WARNING  django.request:log.py:224 Not Found: /api/public/v2/importmetadata/None/
=============================================================================== warnings summary ================================================================================

but changing into the retrieve function as pk == "this is not a UUID" it worked(gives 400 response) only for ImportMetadataViewset

Copy link
Member

@ozer550 ozer550 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested some changes involving throwing a 404 when the pk is None. I would also suggest to change the get_object call to get_object_or_404 to maintain consistency with studio as commented here by @rtibbles . I think @jredrejo also agrees with this?

kolibri/core/content/api.py Show resolved Hide resolved
kolibri/core/content/test/test_content_app.py Outdated Show resolved Hide resolved
kolibri/core/content/test/test_public_api.py Show resolved Hide resolved
@manzil-infinity180
Copy link
Contributor Author

@jredrejo @ozer550 please review it!

@MisRob
Copy link
Member

MisRob commented Nov 14, 2024

Thanks all and @manzil-infinity180 welcome and thanks for working on what seems to be your first contribution to Kolibri!

@ozer550 ozer550 self-assigned this Nov 14, 2024
Copy link
Member

@ozer550 ozer550 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little more clarity on some of the thoughts mentioned earlier. Feel free to ask any more questions to clarify!

@@ -861,13 +860,8 @@ class ContentNodeViewset(InternalContentNodeMixin, RemoteMixin, ReadOnlyValuesVi
pagination_class = OptionalContentNodePagination

def retrieve(self, request, pk=None):

try:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @manzil-infinity180! We still want this functionality of checking if the pk is a valid UUID or not. We want both of the checks that if the UUID is invalid then we throw a 400 and if it is None then we would raise 404. so both the checks should simultaneously exist.

kolibri/core/content/public_api.py Outdated Show resolved Hide resolved
kolibri/core/content/test/test_content_app.py Outdated Show resolved Hide resolved
@manzil-infinity180
Copy link
Contributor Author

manzil-infinity180 commented Nov 15, 2024

@ozer550 Hello, i implemented as you intended above
But checking with the UUID i am getting 400 response code even if i pass pk as NONE or invalid UUID as pk (ImportMetadataViewset)
and 404 for both pk as None and invalid uuid (ContentNodeViewset)
Let me know is i am doing any thing wrong?


If i can replace None with some valid UUID but not content node in test like this then only it will hit this get_object_or_404 ( i guess UUID taking None as invalid UUID)

def test_import_metadata_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:importmetadata-detail",
                kwargs={"pk": "20f5484b88ae49b08af03a389b4917dd"},
            )
        )
        self.assertEqual(response.status_code, 404)

@ozer550
Copy link
Member

ozer550 commented Nov 18, 2024

@ozer550 Hello, i implemented as you intended above But checking with the UUID i am getting 400 response code even if i pass pk as NONE or invalid UUID as pk (ImportMetadataViewset) and 404 for both pk as None and invalid uuid (ContentNodeViewset) Let me know is i am doing any thing wrong? If i can replace None with some valid UUID but not content node in test like this then only it will hit this get_object_or_404 ( i guess UUID taking None as invalid UUID)

def test_import_metadata_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:importmetadata-detail",
                kwargs={"pk": "20f5484b88ae49b08af03a389b4917dd"},
            )
        )
        self.assertEqual(response.status_code, 404)

So the current tests that you have implemented are failing?

@manzil-infinity180
Copy link
Contributor Author

manzil-infinity180 commented Nov 18, 2024

@ozer550 Hello, i implemented as you intended above But checking with the UUID i am getting 400 response code even if i pass pk as NONE or invalid UUID as pk (ImportMetadataViewset) and 404 for both pk as None and invalid uuid (ContentNodeViewset) Let me know is i am doing any thing wrong? If i can replace None with some valid UUID but not content node in test like this then only it will hit this get_object_or_404 ( i guess UUID taking None as invalid UUID)

def test_import_metadata_pk(self):
        response = self.client.get(
            reverse(
                "kolibri:core:importmetadata-detail",
                kwargs={"pk": "20f5484b88ae49b08af03a389b4917dd"},
            )
        )
        self.assertEqual(response.status_code, 404)

So the current tests that you have implemented are failing?

Yeah only two test passing, for when pk is none (Content node Viewset) and when pk is invalid (ImportMetadataViewset)

Copy link
Member

@ozer550 ozer550 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of corrections from myside over things that I overlooked! we are almost there.

kolibri/core/content/public_api.py Show resolved Hide resolved
kolibri/core/content/test/test_public_api.py Outdated Show resolved Hide resolved
kolibri/core/content/api.py Outdated Show resolved Hide resolved
@manzil-infinity180
Copy link
Contributor Author

@ozer550 done , review it

Copy link
Member

@ozer550 ozer550 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @manzil-infinity180! I know we iterated quite a lot of times on this but we both learnt new things. Congratulations on your first contribution to kolibri. Looking forward towards more!

@MisRob
Copy link
Member

MisRob commented Nov 27, 2024

@jredrejo was all your feedback addressed and do you feel good about merging?

Copy link
Contributor

@m3tal10 m3tal10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. This ensures that if the PK is not available then the response must raise a 404(not found) as per requirements and if the pk is not a valid UUID then it should raise a ValueError 400(bad request). The tests also ensure the validity of the response perfectly.

Copy link
Member

@jredrejo jredrejo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jredrejo jredrejo merged commit 7ecaf30 into learningequality:develop Dec 2, 2024
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DEV: backend Python, databases, networking, filesystem... TODO: needs review Waiting for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ensure Consistent 400 Response for Invalid Input in Kolibri Public Content APIs with Studio
5 participants