Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
course-discovery
Commits
098dd992
Commit
098dd992
authored
Apr 11, 2016
by
Clinton Blackburn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added username filtering to catalog list endpoint
ECOM-4087
parent
6ea078e8
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
79 additions
and
13 deletions
+79
-13
course_discovery/apps/api/filters.py
+33
-2
course_discovery/apps/api/v1/tests/test_views/test_catalogs.py
+46
-11
No files found.
course_discovery/apps/api/filters.py
View file @
098dd992
from
django.contrib.auth
import
get_user_model
from
django.utils.translation
import
ugettext
as
_
from
dry_rest_permissions.generics
import
DRYPermissionFiltersBase
from
guardian.shortcuts
import
get_objects_for_user
from
rest_framework.exceptions
import
PermissionDenied
,
NotFound
User
=
get_user_model
()
class
PermissionsFilter
(
DRYPermissionFiltersBase
):
def
filter_list_queryset
(
self
,
request
,
queryset
,
view
):
""" Filters the list queryset, returning only the objects accessible by the user. """
""" Filters the list queryset, returning only the objects accessible by the user.
If a username parameter is passed on the querystring, the filter will will return objects accessible by
the user corresponding to the given username. NOTE: This functionality is only accessible to staff users.
Raises:
PermissionDenied -- If a username querystring parameter is specified, but the user is not a staff user.
Http404 -- If no `User` corresponding to the given username exists.
Returns:
`QuerySet`
"""
perm
=
queryset
.
model
.
get_permission
(
'view'
)
return
get_objects_for_user
(
request
.
user
,
perm
)
user
=
request
.
user
username
=
request
.
query_params
.
get
(
'username'
,
None
)
if
username
:
if
request
.
user
.
is_staff
:
try
:
user
=
User
.
objects
.
get
(
username
=
username
)
except
User
.
DoesNotExist
:
raise
NotFound
(
_
(
'No user with the username [{username}] exists.'
)
.
format
(
username
=
username
))
else
:
raise
PermissionDenied
(
_
(
'Only staff users are permitted to filter by username. Remove the username parameter.'
)
)
return
get_objects_for_user
(
user
,
perm
)
course_discovery/apps/api/v1/tests/test_views/test_catalogs.py
View file @
098dd992
...
...
@@ -20,6 +20,7 @@ from course_discovery.apps.course_metadata.tests.factories import CourseRunFacto
@ddt.ddt
class
CatalogViewSetTests
(
ElasticsearchTestMixin
,
SerializationMixin
,
OAuth2Mixin
,
APITestCase
):
""" Tests for the catalog resource. """
catalog_list_url
=
reverse
(
'api:v1:catalog-list'
)
def
setUp
(
self
):
super
(
CatalogViewSetTests
,
self
)
.
setUp
()
...
...
@@ -39,7 +40,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
'query'
:
query
}
response
=
self
.
client
.
post
(
reverse
(
'api:v1:catalog-list'
)
,
data
,
format
=
'json'
,
**
headers
)
response
=
self
.
client
.
post
(
self
.
catalog_list_url
,
data
,
format
=
'json'
,
**
headers
)
self
.
assertEqual
(
response
.
status_code
,
201
)
catalog
=
Catalog
.
objects
.
latest
()
...
...
@@ -47,18 +48,19 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
self
.
assertEqual
(
catalog
.
name
,
name
)
self
.
assertEqual
(
catalog
.
query
,
query
)
def
grant_catalog_permission_to_user
(
self
,
user
,
action
):
def
grant_catalog_permission_to_user
(
self
,
user
,
action
,
catalog
=
None
):
""" Grant the user access to view `self.catalog`. """
catalog
=
catalog
or
self
.
catalog
perm
=
'{action}_catalog'
.
format
(
action
=
action
)
user
.
add_obj_perm
(
perm
,
self
.
catalog
)
self
.
assertTrue
(
user
.
has_perm
(
'catalogs.'
+
perm
,
self
.
catalog
))
user
.
add_obj_perm
(
perm
,
catalog
)
self
.
assertTrue
(
user
.
has_perm
(
'catalogs.'
+
perm
,
catalog
))
def
test_create_without_authentication
(
self
):
""" Verify authentication is required when creating, updating, or deleting a catalog. """
self
.
client
.
logout
()
Catalog
.
objects
.
all
()
.
delete
()
response
=
self
.
client
.
post
(
reverse
(
'api:v1:catalog-list'
)
,
{},
format
=
'json'
)
response
=
self
.
client
.
post
(
self
.
catalog_list_url
,
{},
format
=
'json'
)
self
.
assertEqual
(
response
.
status_code
,
403
)
self
.
assertEqual
(
Catalog
.
objects
.
count
(),
0
)
...
...
@@ -120,9 +122,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
def
test_list
(
self
):
""" Verify the endpoint returns a list of all catalogs. """
url
=
reverse
(
'api:v1:catalog-list'
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
self
.
catalog_list_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
(
Catalog
.
objects
.
all
(),
many
=
True
))
...
...
@@ -189,16 +189,15 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
""" Verify only catalogs accessible to the user are returned in the list view. """
user
=
UserFactory
(
is_staff
=
False
,
is_superuser
=
False
)
self
.
client
.
force_authenticate
(
user
)
url
=
reverse
(
'api:v1:catalog-list'
)
# An user with no permissions should not see any catalogs
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
self
.
catalog_list_
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
[])
# The client should be able to see permissions for which it has access
self
.
grant_catalog_permission_to_user
(
user
,
'view'
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
self
.
catalog_list_
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
([
self
.
catalog
],
many
=
True
))
...
...
@@ -222,3 +221,39 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
self
.
grant_catalog_permission_to_user
(
user
,
'delete'
)
response
=
self
.
client
.
delete
(
url
)
self
.
assertEqual
(
response
.
status_code
,
204
)
def
test_username_filter_as_non_staff_user
(
self
):
""" Verify HTTP 403 is returned when a non-staff user attempts to filter the Catalog list by username. """
user
=
UserFactory
(
is_staff
=
False
,
is_superuser
=
False
)
self
.
client
.
force_authenticate
(
user
)
response
=
self
.
client
.
get
(
self
.
catalog_list_url
+
'?username=jack'
)
self
.
assertEqual
(
response
.
status_code
,
403
)
expected
=
{
'detail'
:
'Only staff users are permitted to filter by username. Remove the username parameter.'
}
self
.
assertDictEqual
(
response
.
data
,
expected
)
def
test_username_filter_as_staff_user
(
self
):
""" Verify a list of Catalogs accessible by the given user is returned when filtering by username as a
staff user. """
user
=
UserFactory
(
is_staff
=
False
,
is_superuser
=
False
)
catalog
=
CatalogFactory
()
path
=
'{root}?username={username}'
.
format
(
root
=
self
.
catalog_list_url
,
username
=
user
.
username
)
response
=
self
.
client
.
get
(
path
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
[])
self
.
grant_catalog_permission_to_user
(
user
,
'view'
,
catalog
)
response
=
self
.
client
.
get
(
path
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
([
catalog
],
many
=
True
))
def
test_username_filter_as_staff_user_with_invalid_username
(
self
):
""" Verify HTTP 404 is returned if the given username does not correspond to an actual user. """
username
=
'jack'
path
=
'{root}?username={username}'
.
format
(
root
=
self
.
catalog_list_url
,
username
=
username
)
response
=
self
.
client
.
get
(
path
)
self
.
assertEqual
(
response
.
status_code
,
404
)
expected
=
{
'detail'
:
'No user with the username [{username}] exists.'
.
format
(
username
=
username
)}
self
.
assertDictEqual
(
response
.
data
,
expected
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment