Merge pull request #1325 from edx/dhm/paginate_assets
Add asset pagination
This commit is contained in:
@@ -6,19 +6,20 @@ Unit tests for the asset upload endpoint.
|
||||
#pylint: disable=W0621
|
||||
#pylint: disable=W0212
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from io import BytesIO
|
||||
from pytz import UTC
|
||||
import json
|
||||
import re
|
||||
from unittest import TestCase, skip
|
||||
from .utils import CourseTestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from contentstore.views import assets
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
from xmodule.contentstore.content import StaticContent, XASSET_LOCATION_TAG
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.contentstore.django import contentstore
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.xml_importer import import_from_xml
|
||||
import json
|
||||
|
||||
|
||||
class AssetsTestCase(CourseTestCase):
|
||||
@@ -147,3 +148,84 @@ class LockAssetTestCase(CourseTestCase):
|
||||
resp_asset = post_asset_update(False)
|
||||
self.assertFalse(resp_asset['locked'])
|
||||
verify_asset_locked_state(False)
|
||||
|
||||
|
||||
class TestAssetIndex(CourseTestCase):
|
||||
"""
|
||||
Test getting asset lists via http (Note, the assets don't actually exist)
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create fake asset entries for the other tests to use
|
||||
"""
|
||||
super(TestAssetIndex, self).setUp()
|
||||
self.entry_filter = self.create_asset_entries(contentstore(), 100)
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Get rid of the entries
|
||||
"""
|
||||
contentstore().fs_files.remove(self.entry_filter)
|
||||
|
||||
def create_asset_entries(self, cstore, number):
|
||||
"""
|
||||
Create the fake entries
|
||||
"""
|
||||
course_filter = Location(
|
||||
XASSET_LOCATION_TAG, category='asset', course=self.course.location.course, org=self.course.location.org
|
||||
)
|
||||
base_entry = {
|
||||
'displayname': 'foo.jpg',
|
||||
'chunkSize': 262144,
|
||||
'length': 0,
|
||||
'uploadDate': datetime(2012, 1, 2, 0, 0),
|
||||
'contentType': 'image/jpeg',
|
||||
}
|
||||
for i in range(number):
|
||||
base_entry['displayname'] = '{:03x}.jpeg'.format(i)
|
||||
base_entry['uploadDate'] += timedelta(hours=i)
|
||||
base_entry['_id'] = course_filter.replace(name=base_entry['displayname']).dict()
|
||||
cstore.fs_files.insert(base_entry)
|
||||
|
||||
return course_filter.dict()
|
||||
|
||||
ASSET_LIST_RE = re.compile(r'AssetCollection\((.*)\);$', re.MULTILINE)
|
||||
|
||||
def check_page_content(self, resp_content, entry_count, last_date=None):
|
||||
"""
|
||||
:param entry_count:
|
||||
:param last_date:
|
||||
"""
|
||||
match = self.ASSET_LIST_RE.search(resp_content)
|
||||
asset_list = json.loads(match.group(1))
|
||||
self.assertEqual(len(asset_list), entry_count)
|
||||
for row in asset_list:
|
||||
datetext = row['date_added']
|
||||
parsed_date = datetime.strptime(datetext, "%b %d, %Y at %H:%M UTC")
|
||||
if last_date is None:
|
||||
last_date = parsed_date
|
||||
else:
|
||||
self.assertGreaterEqual(last_date, parsed_date)
|
||||
return last_date
|
||||
|
||||
def test_query_assets(self):
|
||||
"""
|
||||
The actual test
|
||||
"""
|
||||
# get all
|
||||
asset_url = reverse(
|
||||
'asset_index',
|
||||
kwargs={
|
||||
'org': self.course.location.org,
|
||||
'course': self.course.location.course,
|
||||
'name': self.course.location.name
|
||||
}
|
||||
)
|
||||
resp = self.client.get(asset_url)
|
||||
self.check_page_content(resp.content, 100)
|
||||
# get first page of 10
|
||||
resp = self.client.get(asset_url + "/max/10")
|
||||
last_date = self.check_page_content(resp.content, 10)
|
||||
# get next of 20
|
||||
resp = self.client.get(asset_url + "/start/10/max/20")
|
||||
last_date = self.check_page_content(resp.content, 20, last_date)
|
||||
|
||||
@@ -23,6 +23,7 @@ from .access import get_location_and_verify_access
|
||||
from util.json_request import JsonResponse
|
||||
import json
|
||||
from django.utils.translation import ugettext as _
|
||||
from pymongo import DESCENDING
|
||||
|
||||
|
||||
__all__ = ['asset_index', 'upload_asset']
|
||||
@@ -30,11 +31,14 @@ __all__ = ['asset_index', 'upload_asset']
|
||||
|
||||
@login_required
|
||||
@ensure_csrf_cookie
|
||||
def asset_index(request, org, course, name):
|
||||
def asset_index(request, org, course, name, start=None, maxresults=None):
|
||||
"""
|
||||
Display an editable asset library
|
||||
|
||||
org, course, name: Attributes of the Location for the item to edit
|
||||
|
||||
:param start: which index of the result list to start w/, used for paging results
|
||||
:param maxresults: maximum results
|
||||
"""
|
||||
location = get_location_and_verify_access(request, org, course, name)
|
||||
|
||||
@@ -47,10 +51,17 @@ def asset_index(request, org, course, name):
|
||||
course_module = modulestore().get_item(location)
|
||||
|
||||
course_reference = StaticContent.compute_location(org, course, name)
|
||||
assets = contentstore().get_all_content_for_course(course_reference)
|
||||
|
||||
# sort in reverse upload date order
|
||||
assets = sorted(assets, key=lambda asset: asset['uploadDate'], reverse=True)
|
||||
if maxresults is not None:
|
||||
maxresults = int(maxresults)
|
||||
start = int(start) if start else 0
|
||||
assets = contentstore().get_all_content_for_course(
|
||||
course_reference, start=start, maxresults=maxresults,
|
||||
sort=[('uploadDate', DESCENDING)]
|
||||
)
|
||||
else:
|
||||
assets = contentstore().get_all_content_for_course(
|
||||
course_reference, sort=[('uploadDate', DESCENDING)]
|
||||
)
|
||||
|
||||
asset_json = []
|
||||
for asset in assets:
|
||||
|
||||
@@ -71,7 +71,7 @@ urlpatterns = patterns('', # nopep8
|
||||
url(r'^edit_tabs/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$',
|
||||
'contentstore.views.edit_tabs', name='edit_tabs'),
|
||||
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/assets/(?P<name>[^/]+)$',
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/assets/(?P<name>[^/]+)(/start/(?P<start>\d+))?(/max/(?P<maxresults>\d+))?$',
|
||||
'contentstore.views.asset_index', name='asset_index'),
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/assets/(?P<name>[^/]+)/(?P<asset_id>.+)?.*$',
|
||||
'contentstore.views.assets.update_asset', name='update_asset'),
|
||||
|
||||
Reference in New Issue
Block a user