Commit 2cb2233d by Zia Fazal

initial change set. add org autocomplete

added unit tests and fixed JS tests

added bok choy tests

fixed broken botchoy tests

fixed course discovery broken test

removed monkey patch at class level

changes after feedback from matte
parent 8b3ea56d
......@@ -2,8 +2,10 @@
Test view handler for rerun (and eventually create)
"""
import ddt
from mock import patch
from django.test.client import RequestFactory
from django.core.urlresolvers import reverse
from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
......@@ -15,6 +17,10 @@ from student.tests.factories import UserFactory
from contentstore.tests.utils import AjaxEnabledTestClient, parse_json
from datetime import datetime
from xmodule.course_module import CourseFields
from util.organizations_helpers import (
add_organization,
get_course_organizations,
)
@ddt.ddt
......@@ -33,7 +39,7 @@ class TestCourseListing(ModuleStoreTestCase):
self.factory = RequestFactory()
self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password='test')
self.course_create_rerun_url = reverse('course_handler')
source_course = CourseFactory.create(
org='origin',
number='the_beginning',
......@@ -57,7 +63,7 @@ class TestCourseListing(ModuleStoreTestCase):
"""
Just testing the functionality the view handler adds over the tasks tested in test_clone_course
"""
response = self.client.ajax_post('/course/', {
response = self.client.ajax_post(self.course_create_rerun_url, {
'source_course_key': unicode(self.source_course_key),
'org': self.source_course_key.org, 'course': self.source_course_key.course, 'run': 'copy',
'display_name': 'not the same old name',
......@@ -76,7 +82,7 @@ class TestCourseListing(ModuleStoreTestCase):
Tests newly created course has web certs enabled by default.
"""
with modulestore().default_store(store):
response = self.client.ajax_post('/course/', {
response = self.client.ajax_post(self.course_create_rerun_url, {
'org': 'orgX',
'number': 'CS101',
'display_name': 'Course with web certs enabled',
......@@ -87,3 +93,66 @@ class TestCourseListing(ModuleStoreTestCase):
new_course_key = CourseKey.from_string(data['course_key'])
course = self.store.get_course(new_course_key)
self.assertTrue(course.cert_html_view_enabled)
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': False})
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
def test_course_creation_without_org_app_enabled(self, store):
"""
Tests course creation workflow should not create course to org
link if organizations_app is not enabled.
"""
with modulestore().default_store(store):
response = self.client.ajax_post(self.course_create_rerun_url, {
'org': 'orgX',
'number': 'CS101',
'display_name': 'Course with web certs enabled',
'run': '2015_T2'
})
self.assertEqual(response.status_code, 200)
data = parse_json(response)
new_course_key = CourseKey.from_string(data['course_key'])
course_orgs = get_course_organizations(new_course_key)
self.assertEqual(course_orgs, [])
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
def test_course_creation_with_org_not_in_system(self, store):
"""
Tests course creation workflow when course organization does not exist
in system.
"""
with modulestore().default_store(store):
response = self.client.ajax_post(self.course_create_rerun_url, {
'org': 'orgX',
'number': 'CS101',
'display_name': 'Course with web certs enabled',
'run': '2015_T2'
})
self.assertEqual(response.status_code, 400)
data = parse_json(response)
self.assertIn(u'Organization you selected does not exist in the system', data['error'])
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
def test_course_creation_with_org_in_system(self, store):
"""
Tests course creation workflow when course organization exist in system.
"""
add_organization({
'name': 'Test Organization',
'short_name': 'orgX',
'description': 'Testing Organization Description',
})
with modulestore().default_store(store):
response = self.client.ajax_post(self.course_create_rerun_url, {
'org': 'orgX',
'number': 'CS101',
'display_name': 'Course with web certs enabled',
'run': '2015_T2'
})
self.assertEqual(response.status_code, 200)
data = parse_json(response)
new_course_key = CourseKey.from_string(data['course_key'])
course_orgs = get_course_organizations(new_course_key)
self.assertEqual(len(course_orgs), 1)
self.assertEqual(course_orgs[0]['short_name'], 'orgX')
......@@ -84,6 +84,11 @@ from util.milestones_helpers import (
is_valid_course_key,
set_prerequisite_courses,
)
from util.organizations_helpers import (
add_organization_course,
get_organization_by_short_name,
organizations_enabled,
)
from util.string_utils import _has_non_ascii_characters
from xmodule.contentstore.content import StaticContent
from xmodule.course_module import CourseFields
......@@ -738,8 +743,17 @@ def _create_new_course(request, org, number, run, fields):
Returns the URL for the course overview page.
Raises DuplicateCourseError if the course already exists
"""
org_data = get_organization_by_short_name(org)
if not org_data and organizations_enabled():
return JsonResponse(
{'error': _('You must link this course to an organization in order to continue. '
'Organization you selected does not exist in the system, '
'you will need to add it to the system')},
status=400
)
store_for_new_course = modulestore().default_modulestore.get_modulestore_type()
new_course = create_new_course_in_store(store_for_new_course, request.user, org, number, run, fields)
add_organization_course(org_data, new_course.id)
return JsonResponse({
'url': reverse_course_url('course_handler', new_course.id),
'course_key': unicode(new_course.id),
......
"""Organizations views for use with Studio."""
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import View
from django.http import HttpResponse
from openedx.core.lib.js_utils import escape_json_dumps
from util.organizations_helpers import get_organizations
class OrganizationListView(View):
"""View rendering organization list as json.
This view renders organization list json which is used in org
autocomplete while creating new course.
"""
@method_decorator(login_required)
def get(self, request, *args, **kwargs):
"""Returns organization list as json."""
organizations = get_organizations()
org_names_list = [(org["short_name"]) for org in organizations]
return HttpResponse(escape_json_dumps(org_names_list), content_type='application/json; charset=utf-8')
"""Tests covering the Organizations listing on the Studio home."""
import json
from mock import patch
from django.core.urlresolvers import reverse
from django.test import TestCase
from util.organizations_helpers import add_organization
from student.tests.factories import UserFactory
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
class TestOrganizationListing(TestCase):
"""Verify Organization listing behavior."""
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
def setUp(self):
super(TestOrganizationListing, self).setUp()
self.staff = UserFactory(is_staff=True)
self.client.login(username=self.staff.username, password='test')
self.org_names_listing_url = reverse('organizations')
self.org_short_names = ["alphaX", "betaX", "orgX"]
for index, short_name in enumerate(self.org_short_names):
add_organization(organization_data={
'name': 'Test Organization %s' % index,
'short_name': short_name,
'description': 'Testing Organization %s Description' % index,
})
def test_organization_list(self):
"""Verify that the organization names list api returns list of organization short names."""
response = self.client.get(self.org_names_listing_url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 200)
org_names = json.loads(response.content)
self.assertEqual(org_names, self.org_short_names)
......@@ -109,6 +109,8 @@ YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YO
FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = True
FEATURES['ORGANIZATIONS_APP'] = True
SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine"
# Path at which to store the mock index
MOCK_SEARCH_BACKING_FILE = (
......
......@@ -180,6 +180,8 @@ FEATURES = {
# Special Exams, aka Timed and Proctored Exams
'ENABLE_SPECIAL_EXAMS': False,
'ORGANIZATIONS_APP': False,
}
ENABLE_JASMINE = False
......@@ -924,6 +926,9 @@ OPTIONAL_APPS = (
# milestones
'milestones',
# Organizations App (http://github.com/edx/edx-organizations)
'organizations',
)
......
......@@ -91,7 +91,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie
$('.new-course-save').on('click', saveNewCourse);
$cancelButton.bind('click', makeCancelHandler('course'));
CancelOnEscape($cancelButton);
CreateCourseUtils.setupOrgAutocomplete();
CreateCourseUtils.configureHandlers();
};
......
......@@ -41,6 +41,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
var requests = AjaxHelpers.requests(this);
var redirectSpy = spyOn(ViewUtils, 'redirect');
$('.new-course-button').click()
AjaxHelpers.expectJsonRequest(requests, 'GET', '/organizations');
AjaxHelpers.respondWithJson(requests, ['DemoX', 'DemoX2', 'DemoX3']);
fillInFields('DemoX', 'DM101', '2014', 'Demo course');
$('.new-course-save').click();
AjaxHelpers.expectJsonRequest(requests, 'POST', '/course/', {
......@@ -53,11 +55,14 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
url: 'dummy_test_url'
});
expect(redirectSpy).toHaveBeenCalledWith('dummy_test_url');
$(".new-course-org").autocomplete("destroy");
});
it("displays an error when saving fails", function () {
var requests = AjaxHelpers.requests(this);
$('.new-course-button').click();
AjaxHelpers.expectJsonRequest(requests, 'GET', '/organizations');
AjaxHelpers.respondWithJson(requests, ['DemoX', 'DemoX2', 'DemoX3']);
fillInFields('DemoX', 'DM101', '2014', 'Demo course');
$('.new-course-save').click();
AjaxHelpers.respondWithJson(requests, {
......@@ -67,6 +72,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
expect($('#course_creation_error')).toContainText('error message');
expect($('.new-course-save')).toHaveClass('is-disabled');
expect($('.new-course-save')).toHaveAttr('aria-disabled', 'true');
$(".new-course-org").autocomplete("destroy");
});
it("saves new libraries", function () {
......
......@@ -11,6 +11,14 @@ define(["jquery", "gettext", "common/js/components/utils/view_utils", "js/views/
CreateUtilsFactory.call(this, selectors, classes, keyLengthViolationMessage, keyFieldSelectors, nonEmptyCheckFieldSelectors);
this.setupOrgAutocomplete = function(){
$.getJSON('/organizations', function (data) {
$(selectors.org).autocomplete({
source: data
});
});
};
this.create = function (courseInfo, errorHandler) {
$.postJSON(
'/course/',
......
......@@ -157,3 +157,35 @@
}
}
}
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 0;
cursor: default;
@include linear-gradient($gray-l5, $white);
border-right: 1px solid $gray-l2;
border-bottom: 1px solid $gray-l2;
border-left: 1px solid $gray-l2;
background-color: $gray-l5;
box-shadow: inset 0 1px 2px $shadow-l1;
color: $color-copy-emphasized;
li.ui-menu-item{
padding: 0;
margin: 0;
a {
color: $color-copy-emphasized;
}
a.ui-state-focus{
border: none;
background-color: $blue;
background: $blue;
color: $white;
}
}
}
......@@ -4,7 +4,7 @@ from django.conf.urls import patterns, include, url
from ratelimitbackend import admin
from cms.djangoapps.contentstore.views.program import ProgramAuthoringView, ProgramsIdTokenView
from cms.djangoapps.contentstore.views.organization import OrganizationListView
admin.autodiscover()
......@@ -41,6 +41,7 @@ urlpatterns = patterns(
url(r'^not_found$', 'contentstore.views.not_found', name='not_found'),
url(r'^server_error$', 'contentstore.views.server_error', name='server_error'),
url(r'^organizations$', OrganizationListView.as_view(), name='organizations'),
# temporary landing page for edge
url(r'^edge$', 'contentstore.views.edge', name='edge'),
......
......@@ -10,7 +10,7 @@ def add_organization(organization_data):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return None
from organizations import api as organizations_api
return organizations_api.add_organization(organization_data=organization_data)
......@@ -20,7 +20,7 @@ def add_organization_course(organization_data, course_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return None
from organizations import api as organizations_api
return organizations_api.add_organization_course(organization_data=organization_data, course_key=course_id)
......@@ -30,17 +30,31 @@ def get_organization(organization_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return []
from organizations import api as organizations_api
return organizations_api.get_organization(organization_id)
def get_organization_by_short_name(organization_short_name):
"""
Client API operation adapter/wrapper
"""
if not organizations_enabled():
return None
from organizations import api as organizations_api
from organizations.exceptions import InvalidOrganizationException
try:
return organizations_api.get_organization_by_short_name(organization_short_name)
except InvalidOrganizationException:
return None
def get_organizations():
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return []
from organizations import api as organizations_api
# Due to the way unit tests run for edx-platform, models are not yet available at the time
......@@ -58,7 +72,7 @@ def get_organization_courses(organization_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return []
from organizations import api as organizations_api
return organizations_api.get_organization_courses(organization_id)
......@@ -68,7 +82,14 @@ def get_course_organizations(course_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
if not organizations_enabled():
return []
from organizations import api as organizations_api
return organizations_api.get_course_organizations(course_id)
def organizations_enabled():
"""
Returns boolean indication if organizations app is enabled on not.
"""
return settings.FEATURES.get('ORGANIZATIONS_APP', False)
......@@ -23,6 +23,7 @@ class OrganizationsHelpersTestCase(ModuleStoreTestCase):
self.organization = {
'name': 'Test Organization',
'short_name': 'Orgx',
'description': 'Testing Organization Helpers Library',
}
......@@ -49,3 +50,25 @@ class OrganizationsHelpersTestCase(ModuleStoreTestCase):
def test_add_organization_course_returns_none_when_app_disabled(self):
response = organizations_helpers.add_organization_course(self.organization, self.course.id)
self.assertIsNone(response)
def test_get_organization_by_short_name_when_app_disabled(self):
"""
Tests get_organization_by_short_name api when app is disabled.
"""
response = organizations_helpers.get_organization_by_short_name(self.organization['short_name'])
self.assertIsNone(response)
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
def test_get_organization_by_short_name_when_app_enabled(self):
"""
Tests get_organization_by_short_name api when app is enabled.
"""
response = organizations_helpers.add_organization(organization_data=self.organization)
self.assertIsNotNone(response['id'])
response = organizations_helpers.get_organization_by_short_name(self.organization['short_name'])
self.assertIsNotNone(response['id'])
# fetch non existing org
response = organizations_helpers.get_organization_by_short_name('non_existing')
self.assertIsNone(response)
......@@ -85,6 +85,85 @@ class DashboardPage(PageObject):
"""
self.q(css='.wrapper-create-library .new-library-save').click()
@property
def new_course_button(self):
"""
Returns "New Course" button.
"""
return self.q(css='.new-course-button')
def is_new_course_form_visible(self):
"""
Is the new course form visible?
"""
return self.q(css='.wrapper-create-course').visible
def click_new_course_button(self):
"""
Click "New Course" button
"""
self.q(css='.new-course-button').first.click()
self.wait_for_ajax()
def fill_new_course_form(self, display_name, org, number, run):
"""
Fill out the form to create a new course.
"""
field = lambda fn: self.q(css='.wrapper-create-course #new-course-{}'.format(fn))
field('name').fill(display_name)
field('org').fill(org)
field('number').fill(number)
field('run').fill(run)
def is_new_course_form_valid(self):
"""
Returns `True` if new course form is valid otherwise `False`.
"""
return (
self.q(css='.wrapper-create-course .new-course-save:not(.is-disabled)').present and
not self.q(css='.wrapper-create-course .wrap-error.is-shown').present
)
def submit_new_course_form(self):
"""
Submit the new course form.
"""
self.q(css='.wrapper-create-course .new-course-save').first.click()
self.wait_for_ajax()
@property
def error_notification(self):
"""
Returns error notification element.
"""
return self.q(css='.wrapper-notification-error.is-shown')
@property
def error_notification_message(self):
"""
Returns text of error message.
"""
self.wait_for_element_visibility(
".wrapper-notification-error.is-shown .message", "Error message is visible"
)
return self.error_notification.results[0].find_element_by_css_selector('.message').text
@property
def course_org_field(self):
"""
Returns course organization input.
"""
return self.q(css='.wrapper-create-course #new-course-org')
def select_item_in_autocomplete_widget(self, item_text):
"""
Selects item in autocomplete where text of item matches item_text.
"""
self.wait_for_element_visibility(
".ui-autocomplete .ui-menu-item", "Autocomplete widget is visible"
)
self.q(css='.ui-autocomplete .ui-menu-item a').filter(lambda el: el.text == item_text)[0].click()
def list_courses(self):
"""
List all the courses found on the page's list of libraries.
......@@ -102,6 +181,15 @@ class DashboardPage(PageObject):
}
return self.q(css='.courses li.course-item').map(div2info).results
def has_course(self, org, number, run):
"""
Returns `True` if course for given org, number and run exists on the page otherwise `False`
"""
for course in self.list_courses():
if course['org'] == org and course['number'] == number and course['run'] == run:
return True
return False
def list_libraries(self):
"""
Click the tab to display the available libraries, and return detail of them.
......
......@@ -3,6 +3,7 @@ Test course discovery.
"""
import datetime
import json
import uuid
from bok_choy.web_app_test import WebAppTest
from ..helpers import remove_file
......@@ -34,29 +35,14 @@ class CourseDiscoveryTest(WebAppTest):
super(CourseDiscoveryTest, self).setUp()
self.page = CourseDiscoveryPage(self.browser)
for i in range(10):
org = self.unique_id
number = unicode(i)
for i in range(12):
org = 'test_org'
number = "{}{}".format(str(i), str(uuid.uuid4().get_hex().upper()[0:6]))
run = "test_run"
name = "test course"
name = "test course" if i < 10 else "grass is always greener"
settings = {'enrollment_start': datetime.datetime(1970, 1, 1).isoformat()}
CourseFixture(org, number, run, name, settings=settings).install()
for i in range(2):
org = self.unique_id
number = unicode(i)
run = "test_run"
name = "grass is always greener"
CourseFixture(
org,
number,
run,
name,
settings={
'enrollment_start': datetime.datetime(1970, 1, 1).isoformat()
}
).install()
def _auto_auth(self, username, email, staff):
"""
Logout and login with given credentials.
......
"""
Acceptance tests for course creation.
"""
import uuid
from bok_choy.web_app_test import WebAppTest
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.studio.index import DashboardPage
from ...pages.studio.overview import CourseOutlinePage
class CreateCourseTest(WebAppTest):
"""
Test that we can create a new course the studio home page.
"""
def setUp(self):
"""
Load the helper for the home page (dashboard page)
"""
super(CreateCourseTest, self).setUp()
self.auth_page = AutoAuthPage(self.browser, staff=True)
self.dashboard_page = DashboardPage(self.browser)
self.course_name = "New Course Name"
self.course_org = "orgX"
self.course_number = str(uuid.uuid4().get_hex().upper()[0:6])
self.course_run = "2015_T2"
def test_create_course_with_non_existing_org(self):
"""
Scenario: Ensure that the course creation with non existing org display proper error message.
Given I have filled course creation form with a non existing and all required fields
When I click 'Create' button
Form validation should pass
Then I see the error message explaining reason for failure to create course
"""
self.auth_page.visit()
self.dashboard_page.visit()
self.assertFalse(self.dashboard_page.has_course(
org='testOrg', number=self.course_number, run=self.course_run
))
self.assertTrue(self.dashboard_page.new_course_button.present)
self.dashboard_page.click_new_course_button()
self.assertTrue(self.dashboard_page.is_new_course_form_visible())
self.dashboard_page.fill_new_course_form(
self.course_name, 'testOrg', self.course_number, self.course_run
)
self.assertTrue(self.dashboard_page.is_new_course_form_valid())
self.dashboard_page.submit_new_course_form()
self.assertTrue(self.dashboard_page.error_notification.present)
self.assertIn(
u'Organization you selected does not exist in the system', self.dashboard_page.error_notification_message
)
def test_create_course_with_existing_org(self):
"""
Scenario: Ensure that the course creation with an existing org should be successful.
Given I have filled course creation form with an existing org and all required fields
When I click 'Create' button
Form validation should pass
Then I see the course listing page with newly created course
"""
self.auth_page.visit()
self.dashboard_page.visit()
self.assertFalse(self.dashboard_page.has_course(
org=self.course_org, number=self.course_number, run=self.course_run
))
self.assertTrue(self.dashboard_page.new_course_button.present)
self.dashboard_page.click_new_course_button()
self.assertTrue(self.dashboard_page.is_new_course_form_visible())
self.dashboard_page.fill_new_course_form(
self.course_name, self.course_org, self.course_number, self.course_run
)
self.assertTrue(self.dashboard_page.is_new_course_form_valid())
self.dashboard_page.submit_new_course_form()
# Successful creation of course takes user to course outline page
course_outline_page = CourseOutlinePage(
self.browser,
self.course_org,
self.course_number,
self.course_run
)
course_outline_page.visit()
course_outline_page.wait_for_page()
# Go back to dashboard and verify newly created course exists there
self.dashboard_page.visit()
self.assertTrue(self.dashboard_page.has_course(
org=self.course_org, number=self.course_number, run=self.course_run
))
def test_create_course_with_existing_org_via_autocomplete(self):
"""
Scenario: Ensure that the course creation with an existing org should be successful.
Given I have filled course creation form with an existing org and all required fields
And I selected `Course Organization` input via autocomplete
When I click 'Create' button
Form validation should pass
Then I see the course listing page with newly created course
"""
self.auth_page.visit()
self.dashboard_page.visit()
new_org = 'orgX2'
self.assertFalse(self.dashboard_page.has_course(
org=new_org, number=self.course_number, run=self.course_run
))
self.assertTrue(self.dashboard_page.new_course_button.present)
self.dashboard_page.click_new_course_button()
self.assertTrue(self.dashboard_page.is_new_course_form_visible())
self.dashboard_page.fill_new_course_form(
self.course_name, '', self.course_number, self.course_run
)
self.dashboard_page.course_org_field.fill('org')
self.dashboard_page.select_item_in_autocomplete_widget(new_org)
self.assertTrue(self.dashboard_page.is_new_course_form_valid())
self.dashboard_page.submit_new_course_form()
# Successful creation of course takes user to course outline page
course_outline_page = CourseOutlinePage(
self.browser,
new_org,
self.course_number,
self.course_run
)
course_outline_page.visit()
course_outline_page.wait_for_page()
# Go back to dashboard and verify newly created course exists there
self.dashboard_page.visit()
self.assertTrue(self.dashboard_page.has_course(
org=new_org, number=self.course_number, run=self.course_run
))
[
{
"pk": 99,
"model": "organizations.organization",
"fields": {
"name": "Demo org 1",
"short_name": "orgX",
"description": "Description of organization 1",
"logo": "org1_logo.png",
"active": 1
}
},
{
"pk": 100,
"model": "organizations.organization",
"fields": {
"name": "Demo org 2",
"short_name": "orgX2",
"description": "Description of organization 2",
"logo": "org2_logo.png",
"active": 1
}
},
{
"pk": 101,
"model": "organizations.organization",
"fields": {
"name": "Demo org 3",
"short_name": "orgX3",
"description": "Description of organization 3",
"logo": "org3_logo.png",
"active": 1
}
},
{
"pk": 102,
"model": "organizations.organization",
"fields": {
"name": "Demo org 4",
"short_name": "test_org",
"description": "Description of organization 4",
"logo": "org4_logo.png",
"active": 1
}
}
]
......@@ -93,7 +93,7 @@ git+https://github.com/edx/xblock-utils.git@v1.0.0#egg=xblock-utils==v1.0.0
-e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive
-e git+https://github.com/edx/edx-reverification-block.git@0.0.5#egg=edx-reverification-block==0.0.5
-e git+https://github.com/edx/edx-user-state-client.git@30c0ad4b9f57f8d48d6943eb585ec8a9205f4469#egg=edx-user-state-client
git+https://github.com/edx/edx-organizations.git@release-2015-11-25#egg=edx-organizations==0.1.9
git+https://github.com/edx/edx-organizations.git@release-2015-12-08#egg=edx-organizations==0.2.0
git+https://github.com/edx/edx-proctoring.git@0.11.6#egg=edx-proctoring==0.11.6
git+https://github.com/edx/xblock-lti-consumer.git@v1.0.0#egg=xblock-lti-consumer==v1.0.0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment