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
dry_rest_permissions.generics
import
DRYPermissionFiltersBase
from
guardian.shortcuts
import
get_objects_for_user
from
guardian.shortcuts
import
get_objects_for_user
from
rest_framework.exceptions
import
PermissionDenied
,
NotFound
User
=
get_user_model
()
class
PermissionsFilter
(
DRYPermissionFiltersBase
):
class
PermissionsFilter
(
DRYPermissionFiltersBase
):
def
filter_list_queryset
(
self
,
request
,
queryset
,
view
):
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'
)
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
...
@@ -20,6 +20,7 @@ from course_discovery.apps.course_metadata.tests.factories import CourseRunFacto
@ddt.ddt
@ddt.ddt
class
CatalogViewSetTests
(
ElasticsearchTestMixin
,
SerializationMixin
,
OAuth2Mixin
,
APITestCase
):
class
CatalogViewSetTests
(
ElasticsearchTestMixin
,
SerializationMixin
,
OAuth2Mixin
,
APITestCase
):
""" Tests for the catalog resource. """
""" Tests for the catalog resource. """
catalog_list_url
=
reverse
(
'api:v1:catalog-list'
)
def
setUp
(
self
):
def
setUp
(
self
):
super
(
CatalogViewSetTests
,
self
)
.
setUp
()
super
(
CatalogViewSetTests
,
self
)
.
setUp
()
...
@@ -39,7 +40,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
...
@@ -39,7 +40,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
'query'
:
query
'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
)
self
.
assertEqual
(
response
.
status_code
,
201
)
catalog
=
Catalog
.
objects
.
latest
()
catalog
=
Catalog
.
objects
.
latest
()
...
@@ -47,18 +48,19 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
...
@@ -47,18 +48,19 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
self
.
assertEqual
(
catalog
.
name
,
name
)
self
.
assertEqual
(
catalog
.
name
,
name
)
self
.
assertEqual
(
catalog
.
query
,
query
)
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`. """
""" Grant the user access to view `self.catalog`. """
catalog
=
catalog
or
self
.
catalog
perm
=
'{action}_catalog'
.
format
(
action
=
action
)
perm
=
'{action}_catalog'
.
format
(
action
=
action
)
user
.
add_obj_perm
(
perm
,
self
.
catalog
)
user
.
add_obj_perm
(
perm
,
catalog
)
self
.
assertTrue
(
user
.
has_perm
(
'catalogs.'
+
perm
,
self
.
catalog
))
self
.
assertTrue
(
user
.
has_perm
(
'catalogs.'
+
perm
,
catalog
))
def
test_create_without_authentication
(
self
):
def
test_create_without_authentication
(
self
):
""" Verify authentication is required when creating, updating, or deleting a catalog. """
""" Verify authentication is required when creating, updating, or deleting a catalog. """
self
.
client
.
logout
()
self
.
client
.
logout
()
Catalog
.
objects
.
all
()
.
delete
()
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
(
response
.
status_code
,
403
)
self
.
assertEqual
(
Catalog
.
objects
.
count
(),
0
)
self
.
assertEqual
(
Catalog
.
objects
.
count
(),
0
)
...
@@ -120,9 +122,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
...
@@ -120,9 +122,7 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
def
test_list
(
self
):
def
test_list
(
self
):
""" Verify the endpoint returns a list of all catalogs. """
""" Verify the endpoint returns a list of all catalogs. """
url
=
reverse
(
'api:v1:catalog-list'
)
response
=
self
.
client
.
get
(
self
.
catalog_list_url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
(
Catalog
.
objects
.
all
(),
many
=
True
))
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
(
Catalog
.
objects
.
all
(),
many
=
True
))
...
@@ -189,16 +189,15 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
...
@@ -189,16 +189,15 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
""" Verify only catalogs accessible to the user are returned in the list view. """
""" Verify only catalogs accessible to the user are returned in the list view. """
user
=
UserFactory
(
is_staff
=
False
,
is_superuser
=
False
)
user
=
UserFactory
(
is_staff
=
False
,
is_superuser
=
False
)
self
.
client
.
force_authenticate
(
user
)
self
.
client
.
force_authenticate
(
user
)
url
=
reverse
(
'api:v1:catalog-list'
)
# An user with no permissions should not see any catalogs
# 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
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
[])
self
.
assertListEqual
(
response
.
data
[
'results'
],
[])
# The client should be able to see permissions for which it has access
# The client should be able to see permissions for which it has access
self
.
grant_catalog_permission_to_user
(
user
,
'view'
)
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
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
([
self
.
catalog
],
many
=
True
))
self
.
assertListEqual
(
response
.
data
[
'results'
],
self
.
serialize_catalog
([
self
.
catalog
],
many
=
True
))
...
@@ -222,3 +221,39 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
...
@@ -222,3 +221,39 @@ class CatalogViewSetTests(ElasticsearchTestMixin, SerializationMixin, OAuth2Mixi
self
.
grant_catalog_permission_to_user
(
user
,
'delete'
)
self
.
grant_catalog_permission_to_user
(
user
,
'delete'
)
response
=
self
.
client
.
delete
(
url
)
response
=
self
.
client
.
delete
(
url
)
self
.
assertEqual
(
response
.
status_code
,
204
)
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