diff --git a/cms/djangoapps/contentstore/context_processors.py b/cms/djangoapps/contentstore/context_processors.py index b6046caec4..9d3131dd13 100644 --- a/cms/djangoapps/contentstore/context_processors.py +++ b/cms/djangoapps/contentstore/context_processors.py @@ -1,21 +1,84 @@ import ConfigParser from django.conf import settings +import logging + +log = logging.getLogger(__name__) + + +# Open and parse the configuration file when the module is initialized config_file = open(settings.REPO_ROOT / "docs" / "config.ini") config = ConfigParser.ConfigParser() config.readfp(config_file) -def doc_url(request): - # in the future, we will detect the locale; for now, we will - # hardcode en_us, since we only have English documentation - locale = "en_us" +def doc_url(request=None): # pylint: disable=unused-argument + """ + This function is added in the list of TEMPLATE_CONTEXT_PROCESSORS, which is a django setting for + a tuple of callables that take a request object as their argument and return a dictionary of items + to be merged into the RequestContext. - def get_doc_url(token): - try: - return config.get(locale, token) - except ConfigParser.NoOptionError: - return config.get(locale, "default") + This function returns a dict with get_online_help_info, making it directly available to all mako templates. - return {"doc_url": get_doc_url} + Args: + request: Currently not used, but is passed by django to context processors. + May be used in the future for determining the language of choice. + """ + + def get_online_help_info(page_token=None): + """ + Args: + page_token: A string that identifies the page for which the help information is requested. + It should correspond to an option in the docs/config.ini file. If it doesn't, the "default" + option is used instead. + + Returns: + A dict mapping the following items + * "doc_url" - a string with the url corresponding to the online help location for the given page_token. + * "pdf_url" - a string with the url corresponding to the location of the PDF help file. + """ + + def get_config_value_with_default(section_name, option, default_option="default"): + """ + Args: + section_name: name of the section in the configuration from which the option should be found + option: name of the configuration option + default_option: name of the default configuration option whose value should be returned if the + requested option is not found + """ + try: + return config.get(section_name, option) + except (ConfigParser.NoOptionError, AttributeError): + log.debug("Didn't find a configuration option for '%s' section and '%s' option", section_name, option) + return config.get(section_name, default_option) + + def get_doc_url(): + """ + Returns: + The URL for the documentation + """ + return "{url_base}/{language}/{version}/{page_path}".format( + url_base=config.get("help_settings", "url_base"), + language=get_config_value_with_default("locales", settings.LANGUAGE_CODE), + version=config.get("help_settings", "version"), + page_path=get_config_value_with_default("pages", page_token), + ) + + def get_pdf_url(): + """ + Returns: + The URL for the PDF document using the pdf_settings and the help_settings (version) in the configuration + """ + return "{pdf_base}/{version}/{pdf_file}".format( + pdf_base=config.get("pdf_settings", "pdf_base"), + version=config.get("help_settings", "version"), + pdf_file=config.get("pdf_settings", "pdf_file"), + ) + + return { + "doc_url": get_doc_url(), + "pdf_url": get_pdf_url(), + } + + return {'get_online_help_info': get_online_help_info} diff --git a/cms/djangoapps/contentstore/features/course-export.py b/cms/djangoapps/contentstore/features/course-export.py index a889f292df..580e582f5d 100644 --- a/cms/djangoapps/contentstore/features/course-export.py +++ b/cms/djangoapps/contentstore/features/course-export.py @@ -1,5 +1,6 @@ -# disable missing docstring # pylint: disable=C0111 +# pylint: disable=W0621 +# pylint: disable=W0613 from lettuce import world, step from component_settings_editor_helpers import enter_xml_in_advanced_problem @@ -8,11 +9,16 @@ from xmodule.modulestore.locations import SlashSeparatedCourseKey from contentstore.utils import reverse_usage_url -@step('I export the course$') -def i_export_the_course(step): +@step('I go to the export page$') +def i_go_to_the_export_page(step): world.click_tools() link_css = 'li.nav-course-tools-export a' world.css_click(link_css) + + +@step('I export the course$') +def i_export_the_course(step): + step.given('I go to the export page') world.css_click('a.action-export') @@ -32,7 +38,7 @@ def i_enter_bad_xml(step): @step('I edit and enter an ampersand$') -def i_enter_bad_xml(step): +def i_enter_an_ampersand(step): enter_xml_in_advanced_problem(step, "&") diff --git a/cms/djangoapps/contentstore/features/course_import.py b/cms/djangoapps/contentstore/features/course_import.py index 84b7affe30..42131f097e 100644 --- a/cms/djangoapps/contentstore/features/course_import.py +++ b/cms/djangoapps/contentstore/features/course_import.py @@ -1,5 +1,9 @@ +# pylint: disable=C0111 +# pylint: disable=W0621 +# pylint: disable=W0613 + import os -from lettuce import world +from lettuce import world, step from django.conf import settings @@ -14,7 +18,8 @@ def import_file(filename): world.css_click(outline_css) -def go_to_import(): +@step('I go to the import page$') +def go_to_import(step): menu_css = 'li.nav-course-tools' import_css = 'li.nav-course-tools-import a' world.css_click(menu_css) diff --git a/cms/djangoapps/contentstore/features/help.feature b/cms/djangoapps/contentstore/features/help.feature new file mode 100644 index 0000000000..ef6bfe33cc --- /dev/null +++ b/cms/djangoapps/contentstore/features/help.feature @@ -0,0 +1,61 @@ +@shard_1 +Feature: CMS.Help + As a course author, I am able to access online help + + Scenario: Users can access online help on course listing page + Given There are no courses + And I am logged into Studio + Then I should see online help for "get_started" + + + Scenario: Users can access online help within a course + Given I have opened a new course in Studio + + And I click the course link in My Courses + Then I should see online help for "organizing_course" + + And I go to the course updates page + Then I should see online help for "updates" + + And I go to the pages page + Then I should see online help for "pages" + + And I go to the files and uploads page + Then I should see online help for "files" + + And I go to the textbooks page + Then I should see online help for "textbooks" + + And I select Schedule and Details + Then I should see online help for "setting_up" + + And I am viewing the grading settings + Then I should see online help for "grading" + + And I am viewing the course team settings + Then I should see online help for "course-team" + + And I select the Advanced Settings + Then I should see online help for "index" + + And I select Checklists from the Tools menu + Then I should see online help for "checklist" + + And I go to the import page + Then I should see online help for "import" + + And I go to the export page + Then I should see online help for "export" + + + Scenario: Users can access online help on the unit page + Given I am in Studio editing a new unit + Then I should see online help for "units" + + + Scenario: Users can access online help on the subsection page + Given I have opened a new course section in Studio + And I have added a new subsection + And I click on the subsection + Then I should see online help for "subsections" + diff --git a/cms/djangoapps/contentstore/features/help.py b/cms/djangoapps/contentstore/features/help.py new file mode 100644 index 0000000000..639aad9c01 --- /dev/null +++ b/cms/djangoapps/contentstore/features/help.py @@ -0,0 +1,24 @@ +# pylint: disable=C0111 +# pylint: disable=W0621 +# pylint: disable=W0613 + +from nose.tools import assert_false # pylint: disable=no-name-in-module +from lettuce import step, world + + +@step(u'I should see online help for "([^"]*)"$') +def see_online_help_for(step, page_name): + # make sure the online Help link exists on this page and contains the expected page name + elements_found = world.browser.find_by_xpath( + '//li[contains(@class, "nav-account-help")]//a[contains(@href, "{page_name}")]'.format( + page_name=page_name + ) + ) + assert_false(elements_found.is_empty()) + + # make sure the PDF link on the sock of this page exists + # for now, the PDF link stays constant for all the pages so we just check for "pdf" + elements_found = world.browser.find_by_xpath( + '//section[contains(@class, "sock")]//li[contains(@class, "js-help-pdf")]//a[contains(@href, "pdf")]' + ) + assert_false(elements_found.is_empty()) diff --git a/cms/djangoapps/contentstore/features/problem-editor.py b/cms/djangoapps/contentstore/features/problem-editor.py index b031363d00..a57e5bda01 100644 --- a/cms/djangoapps/contentstore/features/problem-editor.py +++ b/cms/djangoapps/contentstore/features/problem-editor.py @@ -6,7 +6,7 @@ from lettuce import world, step from nose.tools import assert_equal, assert_true # pylint: disable=E0611 from common import type_in_codemirror, open_new_course from advanced_settings import change_value -from course_import import import_file, go_to_import +from course_import import import_file DISPLAY_NAME = "Display Name" MAXIMUM_ATTEMPTS = "Maximum Attempts" @@ -218,11 +218,6 @@ def i_have_empty_course(step): open_new_course() -@step(u'I go to the import page') -def i_go_to_import(_step): - go_to_import() - - @step(u'I import the file "([^"]*)"$') def i_import_the_file(_step, filename): import_file(filename) diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 6118eb3018..6dc95c1925 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -4,6 +4,10 @@ Specific overrides to the base prod settings to make development easier. from .aws import * # pylint: disable=wildcard-import, unused-wildcard-import +# Don't use S3 in devstack, fall back to filesystem +del DEFAULT_FILE_STORAGE +MEDIA_ROOT = "/edx/var/edxapp/uploads" + DEBUG = True USE_I18N = True TEMPLATE_DEBUG = DEBUG diff --git a/cms/templates/asset_index.html b/cms/templates/asset_index.html index 3cb6b34a07..04f6cef0bb 100644 --- a/cms/templates/asset_index.html +++ b/cms/templates/asset_index.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "files" %> <%! from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ diff --git a/cms/templates/base.html b/cms/templates/base.html index 93a3ec4ff7..c5ba8ac3a2 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -264,7 +264,8 @@
- <%include file="widgets/header.html" /> + <% online_help_token = self.online_help_token() if hasattr(self, 'online_help_token') else None %> + <%include file="widgets/header.html" args="online_help_token=online_help_token" />
@@ -276,7 +277,7 @@ - <%include file="widgets/sock.html" /> + <%include file="widgets/sock.html" args="online_help_token=online_help_token" /> % endif <%include file="widgets/footer.html" /> diff --git a/cms/templates/checklists.html b/cms/templates/checklists.html index 90f77683d8..ad75fe3518 100644 --- a/cms/templates/checklists.html +++ b/cms/templates/checklists.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "checklist" %> <%! from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ diff --git a/cms/templates/course_info.html b/cms/templates/course_info.html index 8cddb8a8c5..7a44f142e3 100644 --- a/cms/templates/course_info.html +++ b/cms/templates/course_info.html @@ -2,6 +2,7 @@ from django.utils.translation import ugettext as _ %> <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "updates" %> <%namespace name='static' file='static_content.html'/> diff --git a/cms/templates/edit-tabs.html b/cms/templates/edit-tabs.html index f3825eacc7..cb27bc831d 100644 --- a/cms/templates/edit-tabs.html +++ b/cms/templates/edit-tabs.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "pages" %> <%namespace name='static' file='static_content.html'/> <%! from django.utils.translation import ugettext as _ diff --git a/cms/templates/edit_subsection.html b/cms/templates/edit_subsection.html index 911687d0c5..bfe5c812dd 100644 --- a/cms/templates/edit_subsection.html +++ b/cms/templates/edit_subsection.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "subsection" %> <%! import logging from util.date_utils import get_default_time_display, almost_same_datetime diff --git a/cms/templates/export.html b/cms/templates/export.html index 0c4021d8c5..e41bb299d6 100644 --- a/cms/templates/export.html +++ b/cms/templates/export.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "export" %> <%namespace name='static' file='static_content.html'/> <%! diff --git a/cms/templates/import.html b/cms/templates/import.html index 2c4fdd17d6..af5987f08e 100644 --- a/cms/templates/import.html +++ b/cms/templates/import.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "import" %> <%namespace name='static' file='static_content.html'/> <%! from django.utils.translation import ugettext as _ diff --git a/cms/templates/index.html b/cms/templates/index.html index 4c5a7518a8..2a905a75ae 100644 --- a/cms/templates/index.html +++ b/cms/templates/index.html @@ -1,7 +1,7 @@ <%! from django.utils.translation import ugettext as _ %> <%inherit file="base.html" /> - +<%def name="online_help_token()"><% return "home" %> <%block name="title">${_("My Courses")} <%block name="bodyclass">is-signedin index view-dashboard @@ -275,18 +275,18 @@ require(["domReady!", "jquery", "jquery.form", "js/index"], function(doc, $) { % endif - diff --git a/cms/templates/unit.html b/cms/templates/unit.html index 46d2209869..9bf98b9bfa 100644 --- a/cms/templates/unit.html +++ b/cms/templates/unit.html @@ -1,4 +1,5 @@ <%inherit file="base.html" /> +<%def name="online_help_token()"><% return "unit" %> <%! from contentstore import utils from contentstore.views.helpers import EDITING_TEMPLATES diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index 11fde27f5a..f9052eaf02 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -2,7 +2,9 @@ <%! from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ + from contentstore.context_processors import doc_url %> +<%page args="online_help_token"/>