Commit b5d6b210 by Clinton Blackburn

Merge pull request #9681 from edx/release

Release 2015-09-09
parents f5057b84 020e1649
...@@ -170,6 +170,9 @@ FEATURES = { ...@@ -170,6 +170,9 @@ FEATURES = {
# Teams feature # Teams feature
'ENABLE_TEAMS': True, 'ENABLE_TEAMS': True,
# Teams search feature
'ENABLE_TEAMS_SEARCH': False,
# Show video bumper in Studio # Show video bumper in Studio
'ENABLE_VIDEO_BUMPER': False, 'ENABLE_VIDEO_BUMPER': False,
......
...@@ -281,5 +281,8 @@ SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" ...@@ -281,5 +281,8 @@ SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine"
# teams feature # teams feature
FEATURES['ENABLE_TEAMS'] = True FEATURES['ENABLE_TEAMS'] = True
# teams search
FEATURES['ENABLE_TEAMS_SEARCH'] = True
# Dummy secret key for dev/test # Dummy secret key for dev/test
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
...@@ -10,6 +10,7 @@ import ddt ...@@ -10,6 +10,7 @@ import ddt
from flaky import flaky from flaky import flaky
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from uuid import uuid4 from uuid import uuid4
from unittest import skip
from ..helpers import EventsTestMixin, UniqueCourseTest from ..helpers import EventsTestMixin, UniqueCourseTest
from ...fixtures import LMS_BASE_URL from ...fixtures import LMS_BASE_URL
...@@ -705,6 +706,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): ...@@ -705,6 +706,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
self.browse_teams_page.click_browse_all_teams_link() self.browse_teams_page.click_browse_all_teams_link()
self.assertTrue(self.topics_page.is_browser_on_page()) self.assertTrue(self.topics_page.is_browser_on_page())
@skip('Disabled until search connectivity issues are resolved, see TNL-3206')
def test_search(self): def test_search(self):
""" """
Scenario: User should be able to search for a team Scenario: User should be able to search for a team
......
...@@ -1375,9 +1375,34 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): ...@@ -1375,9 +1375,34 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
self.assertIn('<a class="shopping-cart"', resp.content) self.assertIn('<a class="shopping-cart"', resp.content)
def test_shopping_cart_navigation_link_in_microsite(self): def test_shopping_cart_navigation_link_not_in_microsite_and_not_on_courseware(self):
""" """
Tests shopping cart link is not available in navigation header if request is from a microsite. Tests shopping cart link is available in navigation header if request is not from a microsite
and requested page is not courseware too.
"""
CourseEnrollment.enroll(self.user, self.course_key)
self.add_course_to_user_cart(self.testing_course.id)
resp = self.client.get(reverse('dashboard'))
self.assertEqual(resp.status_code, 200)
self.assertIn('<a class="shopping-cart"', resp.content)
def test_shopping_cart_navigation_link_in_microsite_not_on_courseware(self):
"""
Tests shopping cart link is available in navigation header if request is from a microsite but requested
page is not from courseware.
"""
CourseEnrollment.enroll(self.user, self.course_key)
self.add_course_to_user_cart(self.testing_course.id)
with patch('microsite_configuration.microsite.is_request_in_microsite',
Mock(return_value=True)):
resp = self.client.get(reverse('dashboard'))
self.assertEqual(resp.status_code, 200)
self.assertIn('<a class="shopping-cart"', resp.content)
def test_shopping_cart_navigation_link_in_microsite_courseware_page(self):
"""
Tests shopping cart link is not available in navigation header if request is from a microsite
and requested page is from courseware.
""" """
CourseEnrollment.enroll(self.user, self.course_key) CourseEnrollment.enroll(self.user, self.course_key)
self.add_course_to_user_cart(self.testing_course.id) self.add_course_to_user_cart(self.testing_course.id)
......
...@@ -16,6 +16,11 @@ class AlreadyOnTeamInCourse(TeamAPIRequestError): ...@@ -16,6 +16,11 @@ class AlreadyOnTeamInCourse(TeamAPIRequestError):
pass pass
class ElasticSearchConnectionError(TeamAPIRequestError):
"""System was unable to connect to the configured elasticsearch instance"""
pass
class ImmutableMembershipFieldException(Exception): class ImmutableMembershipFieldException(Exception):
"""An attempt was made to change an immutable field on a CourseTeamMembership model""" """An attempt was made to change an immutable field on a CourseTeamMembership model"""
pass pass
...@@ -53,8 +53,8 @@ class Command(BaseCommand): ...@@ -53,8 +53,8 @@ class Command(BaseCommand):
if len(args) == 0 and not options.get('all', False): if len(args) == 0 and not options.get('all', False):
raise CommandError(u"reindex_course_team requires one or more arguments: <course_team_id>") raise CommandError(u"reindex_course_team requires one or more arguments: <course_team_id>")
elif not settings.FEATURES.get('ENABLE_TEAMS', False): elif not settings.FEATURES.get('ENABLE_TEAMS_SEARCH', False):
raise CommandError(u"ENABLE_TEAMS must be enabled to use course team indexing") raise CommandError(u"ENABLE_TEAMS_SEARCH must be enabled to use course team indexing")
if options.get('all', False): if options.get('all', False):
course_teams = CourseTeam.objects.all() course_teams = CourseTeam.objects.all()
......
...@@ -39,9 +39,9 @@ class ReindexCourseTeamTest(SharedModuleStoreTestCase): ...@@ -39,9 +39,9 @@ class ReindexCourseTeamTest(SharedModuleStoreTestCase):
def test_teams_search_flag_disabled_raises_command_error(self): def test_teams_search_flag_disabled_raises_command_error(self):
""" Test that raises CommandError for disabled feature flag. """ """ Test that raises CommandError for disabled feature flag. """
with mock.patch('django.conf.settings.FEATURES') as features: with mock.patch('django.conf.settings.FEATURES') as features:
features.return_value = {"ENABLE_TEAMS": False} features.return_value = {"ENABLE_TEAMS_SEARCH": False}
with self.assertRaises(SystemExit), nostderr(): with self.assertRaises(SystemExit), nostderr():
with self.assertRaisesRegexp(CommandError, ".* ENABLE_TEAMS must be enabled .*"): with self.assertRaisesRegexp(CommandError, ".* ENABLE_TEAMS_SEARCH must be enabled .*"):
call_command('reindex_course_team') call_command('reindex_course_team')
def test_given_invalid_team_id_raises_command_error(self): def test_given_invalid_team_id_raises_command_error(self):
......
""" Search index used to load data into elasticsearch""" """ Search index used to load data into elasticsearch"""
import logging
from requests import ConnectionError
from django.conf import settings from django.conf import settings
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from search.search_engine_base import SearchEngine from search.search_engine_base import SearchEngine
from .errors import ElasticSearchConnectionError
from .serializers import CourseTeamSerializer, CourseTeam from .serializers import CourseTeamSerializer, CourseTeam
...@@ -15,7 +19,7 @@ class CourseTeamIndexer(object): ...@@ -15,7 +19,7 @@ class CourseTeamIndexer(object):
""" """
INDEX_NAME = "course_team_index" INDEX_NAME = "course_team_index"
DOCUMENT_TYPE_NAME = "course_team" DOCUMENT_TYPE_NAME = "course_team"
ENABLE_SEARCH_KEY = "ENABLE_TEAMS" ENABLE_SEARCH_KEY = "ENABLE_TEAMS_SEARCH"
def __init__(self, course_team): def __init__(self, course_team):
self.course_team = course_team self.course_team = course_team
...@@ -78,7 +82,11 @@ class CourseTeamIndexer(object): ...@@ -78,7 +82,11 @@ class CourseTeamIndexer(object):
Return course team search engine (if feature is enabled). Return course team search engine (if feature is enabled).
""" """
if cls.search_is_enabled(): if cls.search_is_enabled():
return SearchEngine.get_search_engine(index=cls.INDEX_NAME) try:
return SearchEngine.get_search_engine(index=cls.INDEX_NAME)
except ConnectionError as err:
logging.error("Error connecting to elasticsearch: %s", err)
raise ElasticSearchConnectionError
@classmethod @classmethod
def search_is_enabled(cls): def search_is_enabled(cls):
...@@ -93,4 +101,7 @@ def course_team_post_save_callback(**kwargs): ...@@ -93,4 +101,7 @@ def course_team_post_save_callback(**kwargs):
""" """
Reindex object after save. Reindex object after save.
""" """
CourseTeamIndexer.index(kwargs['instance']) try:
CourseTeamIndexer.index(kwargs['instance'])
except ElasticSearchConnectionError:
pass
...@@ -134,7 +134,7 @@ define([ ...@@ -134,7 +134,7 @@ define([
)); ));
}; };
it('can search teams', function () { xit('can search teams', function () {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView(); teamsTabView = createTeamsTabView();
teamsTabView.browseTopic(TeamSpecHelpers.testTopicID); teamsTabView.browseTopic(TeamSpecHelpers.testTopicID);
...@@ -154,7 +154,7 @@ define([ ...@@ -154,7 +154,7 @@ define([
expect(teamsTabView.$('.page-description').text()).toBe('Showing results for "foo"'); expect(teamsTabView.$('.page-description').text()).toBe('Showing results for "foo"');
}); });
it('can clear a search', function () { xit('can clear a search', function () {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView(); teamsTabView = createTeamsTabView();
teamsTabView.browseTopic(TeamSpecHelpers.testTopicID); teamsTabView.browseTopic(TeamSpecHelpers.testTopicID);
...@@ -177,7 +177,7 @@ define([ ...@@ -177,7 +177,7 @@ define([
expect(teamsTabView.$('.page-description').text()).toBe('Test description 1'); expect(teamsTabView.$('.page-description').text()).toBe('Test description 1');
}); });
it('clears the search when navigating away and then back', function () { xit('clears the search when navigating away and then back', function () {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView(); teamsTabView = createTeamsTabView();
teamsTabView.browseTopic(TeamSpecHelpers.testTopicID); teamsTabView.browseTopic(TeamSpecHelpers.testTopicID);
...@@ -199,7 +199,7 @@ define([ ...@@ -199,7 +199,7 @@ define([
expect(teamsTabView.$('.page-description').text()).toBe('Test description 1'); expect(teamsTabView.$('.page-description').text()).toBe('Test description 1');
}); });
it('does not switch to showing results when the search returns an error', function () { xit('does not switch to showing results when the search returns an error', function () {
var requests = AjaxHelpers.requests(this), var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView(); teamsTabView = createTeamsTabView();
teamsTabView.browseTopic(TeamSpecHelpers.testTopicID); teamsTabView.browseTopic(TeamSpecHelpers.testTopicID);
......
...@@ -66,7 +66,7 @@ define([ ...@@ -66,7 +66,7 @@ define([
expect(Backbone.history.navigate.calls[0].args).toContain('browse'); expect(Backbone.history.navigate.calls[0].args).toContain('browse');
}); });
it('gives the search field focus when clicking on the search teams link', function () { xit('gives the search field focus when clicking on the search teams link', function () {
var emptyMembership = TeamSpecHelpers.createMockTeamMemberships([]), var emptyMembership = TeamSpecHelpers.createMockTeamMemberships([]),
teamsView = createTopicTeamsView({ teamMemberships: emptyMembership }); teamsView = createTopicTeamsView({ teamMemberships: emptyMembership });
spyOn($.fn, 'focus').andCallThrough(); spyOn($.fn, 'focus').andCallThrough();
......
...@@ -303,7 +303,7 @@ ...@@ -303,7 +303,7 @@
viewWithHeader = this.createViewWithHeader({ viewWithHeader = this.createViewWithHeader({
subject: topic, subject: topic,
mainView: teamsView, mainView: teamsView,
headerActionsView: searchFieldView, headerActionsView: null, // TODO: add back SearchFieldView when search is enabled
title: options.title, title: options.title,
description: options.description, description: options.description,
breadcrumbs: options.breadcrumbs breadcrumbs: options.breadcrumbs
......
...@@ -57,13 +57,16 @@ ...@@ -57,13 +57,16 @@
}, },
searchTeams: function (event) { searchTeams: function (event) {
var searchField = $('.page-header-search .search-field'); //var searchField = $('.page-header-search .search-field');
event.preventDefault(); event.preventDefault();
searchField.focus(); //searchField.focus();
searchField.select(); //searchField.select();
$('html, body').animate({ //$('html, body').animate({
scrollTop: 0 // scrollTop: 0
}, 500); //}, 500);
// TODO! Will navigate to correct place once required functionality is available
Backbone.history.navigate('browse', {trigger: true});
}, },
showCreateTeamForm: function (event) { showCreateTeamForm: function (event) {
......
...@@ -55,7 +55,7 @@ from .serializers import ( ...@@ -55,7 +55,7 @@ from .serializers import (
add_team_count add_team_count
) )
from .search_indexes import CourseTeamIndexer from .search_indexes import CourseTeamIndexer
from .errors import AlreadyOnTeamInCourse, NotEnrolledInCourseForTeam from .errors import AlreadyOnTeamInCourse, NotEnrolledInCourseForTeam, ElasticSearchConnectionError
TEAM_MEMBERSHIPS_PER_PAGE = 2 TEAM_MEMBERSHIPS_PER_PAGE = 2
TOPICS_PER_PAGE = 12 TOPICS_PER_PAGE = 12
...@@ -351,7 +351,13 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView): ...@@ -351,7 +351,13 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
return Response(error, status=status.HTTP_400_BAD_REQUEST) return Response(error, status=status.HTTP_400_BAD_REQUEST)
result_filter.update({'topic_id': topic_id}) result_filter.update({'topic_id': topic_id})
if text_search and CourseTeamIndexer.search_is_enabled(): if text_search and CourseTeamIndexer.search_is_enabled():
search_engine = CourseTeamIndexer.engine() try:
search_engine = CourseTeamIndexer.engine()
except ElasticSearchConnectionError:
return Response(
build_api_error(ugettext_noop('Error connecting to elasticsearch')),
status=status.HTTP_400_BAD_REQUEST
)
result_filter.update({'course_id': course_id_string}) result_filter.update({'course_id': course_id_string})
search_results = search_engine.search( search_results = search_engine.search(
......
...@@ -633,7 +633,7 @@ PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM = ENV_TOKENS.get( ...@@ -633,7 +633,7 @@ PDF_RECEIPT_COBRAND_LOGO_HEIGHT_MM = ENV_TOKENS.get(
if FEATURES.get('ENABLE_COURSEWARE_SEARCH') or \ if FEATURES.get('ENABLE_COURSEWARE_SEARCH') or \
FEATURES.get('ENABLE_DASHBOARD_SEARCH') or \ FEATURES.get('ENABLE_DASHBOARD_SEARCH') or \
FEATURES.get('ENABLE_COURSE_DISCOVERY') or \ FEATURES.get('ENABLE_COURSE_DISCOVERY') or \
FEATURES.get('ENABLE_TEAMS'): FEATURES.get('ENABLE_TEAMS_SEARCH'):
# Use ElasticSearch as the search engine herein # Use ElasticSearch as the search engine herein
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
......
...@@ -486,6 +486,9 @@ FEATURES['ENABLE_EDXNOTES'] = True ...@@ -486,6 +486,9 @@ FEATURES['ENABLE_EDXNOTES'] = True
# Enable teams feature for tests. # Enable teams feature for tests.
FEATURES['ENABLE_TEAMS'] = True FEATURES['ENABLE_TEAMS'] = True
# Enable teams search for tests.
FEATURES['ENABLE_TEAMS_SEARCH'] = True
# Add milestones to Installed apps for testing # Add milestones to Installed apps for testing
INSTALLED_APPS += ('milestones', 'openedx.core.djangoapps.call_stack_manager') INSTALLED_APPS += ('milestones', 'openedx.core.djangoapps.call_stack_manager')
......
...@@ -97,7 +97,7 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -97,7 +97,7 @@ site_status_msg = get_site_status_msg(course_id)
</ul> </ul>
</li> </li>
</ol> </ol>
% if should_display_shopping_cart_func() and not microsite.is_request_in_microsite(): # see shoppingcart.context_processor.user_has_cart_context_processor % if should_display_shopping_cart_func() and not (course and microsite.is_request_in_microsite()): # see shoppingcart.context_processor.user_has_cart_context_processor
<ol class="user"> <ol class="user">
<li class="primary"> <li class="primary">
<a class="shopping-cart" href="${reverse('shoppingcart.views.show_cart')}"> <a class="shopping-cart" href="${reverse('shoppingcart.views.show_cart')}">
......
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