Skip to content
This repository has been archived by the owner on Jan 3, 2019. It is now read-only.

Adding http_cache parameter to @viewconfig functions #214

Merged
merged 1 commit into from
Mar 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions cnxauthoring/tests/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def login(self, username='user1', password='password', login_url='/login',
def logout(self):
self.testapp.get('/logout', status=302)

def assert_cors_headers(self, response):
def assert_cors_headers(self, response, cache_message_special_case=None):
self.assertEqual(response.headers['Access-Control-Allow-Credentials'],
'true')
self.assertEqual(response.headers['Access-Control-Allow-Origin'],
Expand All @@ -124,6 +124,30 @@ def assert_cors_headers(self, response):
self.assertEqual(response.headers['Access-Control-Allow-Methods'],
'GET, OPTIONS, PUT, POST')

cache_header_dictionary = {
'201 Created':
['max-age=0, must-revalidate, no-cache, no-store, public'],
'200 OK':
['max-age=0, must-revalidate, no-cache, no-store, public'],
'400 Bad Request': [],
'302 Found': [],
'401 Unauthorized': [],
'403 Forbidden': [],
'404 Not Found': [],
}

try:
expected_cache_header = cache_header_dictionary[response.status]
except KeyError:
expected_cache_header = "NO EXPECTED CACHE HEADER"

actual_cache_header = response.headers.getall('Cache-Control')

if cache_message_special_case:
self.assertEqual(actual_cache_header, cache_message_special_case)
else:
self.assertEqual(actual_cache_header, expected_cache_header)


class FunctionalTests(BaseFunctionalTestCase):
def test_login(self):
Expand All @@ -137,7 +161,8 @@ def test_login_redirect_already_logged_in(self):
'/login?redirect=http://example.com/logged_in', status=302)
self.assertEqual(response.headers['Location'],
'http://example.com/logged_in')
self.assert_cors_headers(response)
self.assert_cors_headers(
response, cache_message_special_case=['public'])

def test_login_redirect_loop(self):
self.logout()
Expand Down Expand Up @@ -197,7 +222,8 @@ def test_options(self):

for url in urls:
response = self.testapp.options(url, status=200)
self.assert_cors_headers(response)
self.assert_cors_headers(
response, cache_message_special_case=['public'])
self.assertEqual(response.headers['Content-Length'], '0')

def test_get_content_401(self):
Expand Down
59 changes: 38 additions & 21 deletions cnxauthoring/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
from .storage import storage
from . import utils

NO_CACHE = (0, {'public': True})
TIMED_CACHE = (datetime.timedelta(
weeks=1, days=0, hours=0, minutes=0, seconds=0), {'public': True})
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't look like this is used anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It isn't. I thought that it would be good to keep in a TIMED_CACHE example just in case it proved useful in the future. We can take it out if you think it'll just be distracting.

Copy link
Member

Choose a reason for hiding this comment

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

We can leave it in - probably want to set some non-zero caching at some point.

DEFAULT_CACHE = (None, {'public': True})

logger = logging.getLogger('cnxauthoring')

Expand Down Expand Up @@ -71,7 +75,7 @@ def wrapper(*args, **kwargs):
return wrapper


@view_config(route_name='login')
@view_config(route_name='login', http_cache=DEFAULT_CACHE)
def login(request):
# store where we should redirect to before login
referer = request.referer or '/'
Expand All @@ -81,10 +85,10 @@ def login(request):
if request.unauthenticated_userid:
return httpexceptions.HTTPFound(location=redirect_to)
request.session.update({'redirect_to': redirect_to})
request.authenticated_userid # triggers login
request.authenticated_userid # triggers login


@view_config(route_name='callback')
@view_config(route_name='callback', http_cache=NO_CACHE)
@authenticated_only
def callback(request):
# callback must be protected so that effective_principals is called
Expand All @@ -96,7 +100,7 @@ def callback(request):
raise httpexceptions.HTTPFound(location=redirect_to)


@view_config(route_name='logout')
@view_config(route_name='logout', http_cache=DEFAULT_CACHE)
def logout(request):
forget(request)
referer = request.referer or '/'
Expand All @@ -106,12 +110,14 @@ def logout(request):
raise httpexceptions.HTTPFound(location=redirect_to)


@view_config(route_name='options', request_method='OPTIONS', renderer='string')
@view_config(route_name='options', request_method='OPTIONS',
renderer='string', http_cache=DEFAULT_CACHE)
def options(request):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this need to have the @authenticated_only decorator?

Copy link
Member

Choose a reason for hiding this comment

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

No, this needs to be available at any url and whether you're authenticated or not. Looking at the commit message "Respond to OPTIONS with CORS headers" it was about letting webview use authoring api.

return ''


@view_config(route_name='user-search', request_method='GET', renderer='json')
@view_config(route_name='user-search', request_method='GET',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
def user_search(request):
"""Search for openstax accounts users"""
Expand All @@ -134,7 +140,8 @@ def user_search(request):
return result


@view_config(route_name='profile', request_method='GET', renderer='json')
@view_config(route_name='profile', request_method='GET',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
def profile(request):
return UserSchema().bind().deserialize(
Expand All @@ -161,7 +168,8 @@ def update_content_state(request, content):
pass


@view_config(route_name='user-contents', request_method='GET', renderer='json')
@view_config(route_name='user-contents', request_method='GET',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def user_contents(request):
Expand Down Expand Up @@ -222,7 +230,8 @@ def user_contents(request):
}


@view_config(route_name='get-content-json', request_method='GET', renderer='json')
@view_config(route_name='get-content-json', request_method='GET',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def get_content(request):
Expand All @@ -239,7 +248,8 @@ def get_content(request):
return content


@view_config(route_name='get-resource', request_method='GET')
@view_config(route_name='get-resource', request_method='GET',
http_cache=NO_CACHE)
@authenticated_only
@storage_management
def get_resource(request):
Expand Down Expand Up @@ -370,7 +380,9 @@ def post_content_single(request, cstruct):

return content

@view_config(route_name='post-content', request_method='POST', renderer='json')

@view_config(route_name='post-content', request_method='POST',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def post_content(request):
Expand Down Expand Up @@ -407,7 +419,8 @@ def post_content(request):
return contents


@view_config(route_name='post-resource', request_method='POST', renderer='string')
@view_config(route_name='post-resource', request_method='POST',
renderer='string', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def post_resource(request):
Expand Down Expand Up @@ -482,13 +495,12 @@ def delete_content_single(request, id, user_id=None, raise_error=True):
return True



@view_config(route_name='delete-user-content', request_method='DELETE',
renderer='json')
renderer='json', http_cache=NO_CACHE)
@view_config(route_name='delete-content', request_method='DELETE',
renderer='json')
renderer='json', http_cache=NO_CACHE)
@view_config(route_name='delete-content-multiple', request_method='PUT',
renderer='json')
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def delete_content(request):
Expand All @@ -515,7 +527,9 @@ def delete_content(request):
user_id = request.authenticated_userid
delete_content_single(request, id, user_id=user_id)

@view_config(route_name='put-content', request_method='PUT', renderer='json')

@view_config(route_name='put-content', request_method='PUT',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def put_content(request):
Expand Down Expand Up @@ -572,7 +586,8 @@ def put_content(request):
return content


@view_config(route_name='search-content', request_method='GET', renderer='json')
@view_config(route_name='search-content', request_method='GET',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def search_content(request):
Expand Down Expand Up @@ -661,7 +676,8 @@ def post_to_publishing(request, userid, submitlog, content_ids):
return contents, requests.post(url, files=files, headers=headers)


@view_config(route_name='publish', request_method='POST', renderer='json')
@view_config(route_name='publish', request_method='POST',
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def publish(request):
Expand Down Expand Up @@ -698,7 +714,7 @@ def publish(request):


@view_config(route_name='acceptance-info', request_method='GET',
renderer='json')
renderer='json', http_cache=NO_CACHE)
@authenticated_only
@storage_management
def get_acceptance_info(request):
Expand Down Expand Up @@ -747,7 +763,8 @@ def get_acceptance_info(request):
return info


@view_config(route_name='acceptance-info', request_method=('POST', 'PUT'))
@view_config(route_name='acceptance-info',
request_method=('POST', 'PUT'), http_cache=NO_CACHE)
@authenticated_only
@storage_management
def post_acceptance_info(request):
Expand Down