PLAT-1074 Add support for django-user-tasks
This commit is contained in:
9
cms/djangoapps/contentstore/rules.py
Normal file
9
cms/djangoapps/contentstore/rules.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Authorization rules related to content management.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import user_tasks.rules
|
||||
|
||||
user_tasks.rules.add_rules()
|
||||
@@ -39,9 +39,12 @@ When refering to XBlocks, we use the entry-point name. For example,
|
||||
# want to import all variables from base settings files
|
||||
# pylint: disable=unused-import
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
from datetime import timedelta
|
||||
import lms.envs.common
|
||||
# Although this module itself may not use these imported variables, other dependent modules may.
|
||||
from lms.envs.common import (
|
||||
@@ -300,6 +303,7 @@ LOGIN_URL = EDX_ROOT_URL + '/signin'
|
||||
|
||||
# use the ratelimit backend to prevent brute force attacks
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'rules.permissions.ObjectPermissionBackend',
|
||||
'ratelimitbackend.backends.RateLimitModelBackend',
|
||||
)
|
||||
|
||||
@@ -933,7 +937,13 @@ INSTALLED_APPS = (
|
||||
'django_sites_extensions',
|
||||
|
||||
# additional release utilities to ease automation
|
||||
'release_util'
|
||||
'release_util',
|
||||
|
||||
# rule-based authorization
|
||||
'rules.apps.AutodiscoverRulesConfig',
|
||||
|
||||
# management of user-triggered async tasks (course import/export, etc.)
|
||||
'user_tasks',
|
||||
)
|
||||
|
||||
|
||||
@@ -1212,3 +1222,8 @@ OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application'
|
||||
# Used with Email sending
|
||||
RETRY_ACTIVATION_EMAIL_MAX_ATTEMPTS = 5
|
||||
RETRY_ACTIVATION_EMAIL_TIMEOUT = 0.5
|
||||
|
||||
############## DJANGO-USER-TASKS ##############
|
||||
|
||||
# How long until database records about the outcome of a task and its artifacts get deleted?
|
||||
USER_TASKS_MAX_AGE = timedelta(days=7)
|
||||
|
||||
107
cms/tests/test_user_tasks.py
Normal file
107
cms/tests/test_user_tasks.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
Unit tests for integration of the django-user-tasks app and its REST API.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import override_settings
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
from user_tasks.models import UserTaskArtifact, UserTaskStatus
|
||||
from user_tasks.serializers import ArtifactSerializer, StatusSerializer
|
||||
|
||||
|
||||
# Helper functions for stuff that pylint complains about without disable comments
|
||||
|
||||
def _context(response):
|
||||
"""
|
||||
Get a context dictionary for a serializer appropriate for the given response.
|
||||
"""
|
||||
return {'request': response.wsgi_request} # pylint: disable=no-member
|
||||
|
||||
|
||||
def _data(response):
|
||||
"""
|
||||
Get the serialized data dictionary from the given REST API test response.
|
||||
"""
|
||||
return response.data # pylint: disable=no-member
|
||||
|
||||
|
||||
@override_settings(BROKER_URL='memory://localhost/')
|
||||
class TestUserTasks(APITestCase):
|
||||
"""
|
||||
Tests of the django-user-tasks REST API endpoints.
|
||||
|
||||
Detailed tests of the default authorization rules are in the django-user-tasks code.
|
||||
These tests just verify that the API is exposed and functioning.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = User.objects.create_user('test_user', 'test@example.com', 'password')
|
||||
cls.status = UserTaskStatus.objects.create(
|
||||
user=cls.user, task_id=str(uuid4()), task_class='test_rest_api.sample_task', name='SampleTask 2',
|
||||
total_steps=5)
|
||||
cls.artifact = UserTaskArtifact.objects.create(status=cls.status, text='Lorem ipsum')
|
||||
|
||||
def setUp(self):
|
||||
super(TestUserTasks, self).setUp()
|
||||
self.status.refresh_from_db()
|
||||
self.client.force_authenticate(self.user) # pylint: disable=no-member
|
||||
|
||||
def test_artifact_detail(self):
|
||||
"""
|
||||
Users should be able to access artifacts for tasks they triggered.
|
||||
"""
|
||||
response = self.client.get(reverse('usertaskartifact-detail', args=[self.artifact.uuid]))
|
||||
assert response.status_code == 200
|
||||
serializer = ArtifactSerializer(self.artifact, context=_context(response))
|
||||
assert _data(response) == serializer.data
|
||||
|
||||
def test_artifact_list(self):
|
||||
"""
|
||||
Users should be able to access a list of their tasks' artifacts.
|
||||
"""
|
||||
response = self.client.get(reverse('usertaskartifact-list'))
|
||||
assert response.status_code == 200
|
||||
serializer = ArtifactSerializer(self.artifact, context=_context(response))
|
||||
assert _data(response)['results'] == [serializer.data]
|
||||
|
||||
def test_status_cancel(self):
|
||||
"""
|
||||
Users should be able to cancel tasks they no longer wish to complete.
|
||||
"""
|
||||
response = self.client.post(reverse('usertaskstatus-cancel', args=[self.status.uuid]))
|
||||
assert response.status_code == 200
|
||||
self.status.refresh_from_db()
|
||||
assert self.status.state == UserTaskStatus.CANCELED
|
||||
|
||||
def test_status_delete(self):
|
||||
"""
|
||||
Users should be able to delete their own task status records when they're done with them.
|
||||
"""
|
||||
response = self.client.delete(reverse('usertaskstatus-detail', args=[self.status.uuid]))
|
||||
assert response.status_code == 204
|
||||
assert not UserTaskStatus.objects.filter(pk=self.status.id).exists()
|
||||
|
||||
def test_status_detail(self):
|
||||
"""
|
||||
Users should be able to access status records for tasks they triggered.
|
||||
"""
|
||||
response = self.client.get(reverse('usertaskstatus-detail', args=[self.status.uuid]))
|
||||
assert response.status_code == 200
|
||||
serializer = StatusSerializer(self.status, context=_context(response))
|
||||
assert _data(response) == serializer.data
|
||||
|
||||
def test_status_list(self):
|
||||
"""
|
||||
Users should be able to access a list of their tasks' status records.
|
||||
"""
|
||||
response = self.client.get(reverse('usertaskstatus-list'))
|
||||
assert response.status_code == 200
|
||||
serializer = StatusSerializer([self.status], context=_context(response), many=True)
|
||||
assert _data(response)['results'] == serializer.data
|
||||
@@ -113,6 +113,7 @@ urlpatterns += patterns(
|
||||
url(r'^group_configurations/{}/(?P<group_configuration_id>\d+)(/)?(?P<group_id>\d+)?$'.format(
|
||||
settings.COURSE_KEY_PATTERN), 'group_configurations_detail_handler'),
|
||||
url(r'^api/val/v0/', include('edxval.urls')),
|
||||
url(r'^api/tasks/v0/', include('user_tasks.urls')),
|
||||
)
|
||||
|
||||
JS_INFO_DICT = {
|
||||
|
||||
@@ -34,6 +34,7 @@ django-simple-history==1.6.3
|
||||
django-statici18n==1.1.5
|
||||
django-storages==1.4.1
|
||||
django-method-override==0.1.0
|
||||
django-user-tasks==0.1.1
|
||||
# We need a fix to DRF 3.2.x, for now use it from our own cherry-picked repo
|
||||
#djangorestframework>=3.1,<3.2
|
||||
git+https://github.com/edx/django-rest-framework.git@3c72cb5ee5baebc4328947371195eae2077197b0#egg=djangorestframework==3.2.3
|
||||
@@ -94,6 +95,7 @@ pysrt==0.4.7
|
||||
PyYAML==3.10
|
||||
requests==2.9.1
|
||||
requests-oauthlib==0.4.1
|
||||
rules==1.1.1
|
||||
scipy==0.14.0
|
||||
Shapely==1.2.16
|
||||
singledispatch==3.4.0.2
|
||||
|
||||
Reference in New Issue
Block a user