Commit 3fceb469 by Chris Dodge

Merge branch 'master' of github.com:edx/edx-platform into…

Merge branch 'master' of github.com:edx/edx-platform into feature/cdodge/autoprovision-forums-master
parents 47056954 ce2cbb74
......@@ -26,6 +26,7 @@ Gemfile.lock
conf/locale/en/LC_MESSAGES/*.po
!messages.po
lms/static/sass/*.css
lms/static/sass/application.scss
cms/static/sass/*.css
lms/lib/comment_client/python
nosetests.xml
......
......@@ -475,12 +475,11 @@ class LoncapaProblem(object):
msg = "Error while executing script code: %s" % str(err).replace('<', '&lt;')
raise responsetypes.LoncapaProblemError(msg)
# store code source in context
# Store code source in context, along with the Python path needed to run it correctly.
context['script_code'] = all_code
context['python_path'] = python_path
return context
def _extract_html(self, problemtree): # private
'''
Main (private) function which converts Problem XML tree to HTML.
......
......@@ -286,7 +286,7 @@ class LoncapaResponse(object):
}
try:
safe_exec.safe_exec(code, globals_dict)
safe_exec.safe_exec(code, globals_dict, python_path=self.context['python_path'])
except Exception as err:
msg = 'Error %s in evaluating hint function %s' % (err, hintfn)
msg += "\nSee XML source line %s" % getattr(
......@@ -972,7 +972,7 @@ class CustomResponse(LoncapaResponse):
'ans': ans,
}
globals_dict.update(kwargs)
safe_exec.safe_exec(code, globals_dict, cache=self.system.cache)
safe_exec.safe_exec(code, globals_dict, python_path=self.context['python_path'])
return globals_dict['cfn_return']
return check_function
......
......@@ -414,6 +414,11 @@ def modx_dispatch(request, dispatch, location, course_id):
through the part before the first '?'.
- location -- the module location. Used to look up the XModule instance
- course_id -- defines the course context for this request.
Raises PermissionDenied if the user is not logged in. Raises Http404 if
the location and course_id do not identify a valid module, the module is
not accessible by the user, or the module raises NotFoundError. If the
module raises any other error, it will escape this function.
'''
# ''' (fix emacs broken parsing)
......@@ -442,8 +447,19 @@ def modx_dispatch(request, dispatch, location, course_id):
return HttpResponse(json.dumps({'success': file_too_big_msg}))
p[fileinput_id] = inputfiles
try:
descriptor = modulestore().get_instance(course_id, location)
except ItemNotFoundError:
log.warn(
"Invalid location for course id {course_id}: {location}".format(
course_id=course_id,
location=location
)
)
raise Http404
model_data_cache = ModelDataCache.cache_for_descriptor_descendents(course_id,
request.user, modulestore().get_instance(course_id, location))
request.user, descriptor)
instance = get_module(request.user, request, location, model_data_cache, course_id, grade_bucket_type='ajax')
if instance is None:
......
......@@ -69,19 +69,38 @@ class ModuleRenderTestCase(LoginEnrollmentTestCase):
json.dumps({'success': 'Submission aborted! Your file "%s" is too large (max size: %d MB)' %
(inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE / (1000 ** 2))}))
mock_request_3 = MagicMock()
mock_request_3.POST.copy.return_value = {}
mock_request_3.POST.copy.return_value = {'position': 1}
mock_request_3.FILES = False
mock_request_3.user = UserFactory()
inputfile_2 = Stub()
inputfile_2.size = 1
inputfile_2.name = 'name'
self.assertRaises(ItemNotFoundError, render.modx_dispatch,
mock_request_3, 'dummy', self.location, 'toy')
self.assertRaises(Http404, render.modx_dispatch, mock_request_3, 'dummy',
self.location, self.course_id)
mock_request_3.POST.copy.return_value = {'position': 1}
self.assertIsInstance(render.modx_dispatch(mock_request_3, 'goto_position',
self.location, self.course_id), HttpResponse)
self.assertRaises(
Http404,
render.modx_dispatch,
mock_request_3,
'goto_position',
self.location,
'bad_course_id'
)
self.assertRaises(
Http404,
render.modx_dispatch,
mock_request_3,
'goto_position',
['i4x', 'edX', 'toy', 'chapter', 'bad_location'],
self.course_id
)
self.assertRaises(
Http404,
render.modx_dispatch,
mock_request_3,
'bad_dispatch',
self.location,
self.course_id
)
def test_get_score_bucket(self):
self.assertEquals(render.get_score_bucket(0, 10), 'incorrect')
......
......@@ -114,6 +114,11 @@ DEFAULT_FEEDBACK_EMAIL = ENV_TOKENS.get('DEFAULT_FEEDBACK_EMAIL', DEFAULT_FEEDBA
ADMINS = ENV_TOKENS.get('ADMINS', ADMINS)
SERVER_EMAIL = ENV_TOKENS.get('SERVER_EMAIL', SERVER_EMAIL)
#Theme overrides
THEME_NAME = ENV_TOKENS.get('THEME_NAME', None)
if not THEME_NAME is None:
enable_theme(THEME_NAME)
#Timezone overrides
TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE)
......
......@@ -72,6 +72,7 @@ MITX_FEATURES = {
'ENABLE_PSYCHOMETRICS': False, # real-time psychometrics (eg item response theory analysis in instructor dashboard)
'ENABLE_DJANGO_ADMIN_SITE': False, # set true to enable django's admin site, even on prod (e.g. for course ops)
'ENABLE_SQL_TRACKING_LOGS': False,
'ENABLE_LMS_MIGRATION': False,
'ENABLE_MANUAL_GIT_RELOAD': False,
......@@ -110,6 +111,9 @@ MITX_FEATURES = {
# Enable URL that shows information about the status of variuous services
'ENABLE_SERVICE_STATUS': False,
# Toggle to indicate use of a custom theme
'USE_CUSTOM_THEME': False
}
# Used for A/B testing
......@@ -167,12 +171,12 @@ MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
# This is where Django Template lookup is defined. There are a few of these
# still left lying around.
TEMPLATE_DIRS = (
TEMPLATE_DIRS = [
PROJECT_ROOT / "templates",
COMMON_ROOT / 'templates',
COMMON_ROOT / 'lib' / 'capa' / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates',
)
]
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
......@@ -713,3 +717,31 @@ MKTG_URL_LINK_MAP = {
'HONOR': 'honor',
'PRIVACY': 'privacy_edx',
}
############################### THEME ################################
def enable_theme(theme_name):
"""
Enable the settings for a custom theme, whose files should be stored
in ENV_ROOT/themes/THEME_NAME (e.g., edx_all/themes/stanford).
The THEME_NAME setting should be configured separately since it can't
be set here (this function closes too early). An idiom for doing this
is:
THEME_NAME = "stanford"
enable_theme(THEME_NAME)
"""
MITX_FEATURES['USE_CUSTOM_THEME'] = True
# Calculate the location of the theme's files
theme_root = ENV_ROOT / "themes" / theme_name
# Include the theme's templates in the template search paths
TEMPLATE_DIRS.append(theme_root / 'templates')
MAKO_TEMPLATES['main'].append(theme_root / 'templates')
# Namespace the theme's static files to 'themes/<theme_name>' to
# avoid collisions with default edX static files
STATICFILES_DIRS.append((u'themes/%s' % theme_name,
theme_root / 'static'))
......@@ -31,14 +31,9 @@ def merge_dict(dic1, dic2):
def perform_request(method, url, data_or_params=None, *args, **kwargs):
if data_or_params is None:
data_or_params = {}
tags = [
"{k}:{v}".format(k=k, v=v)
for (k, v) in data_or_params.items() + [("method", method), ("url", url)]
if k != 'api_key'
]
data_or_params['api_key'] = settings.API_KEY
try:
with dog_stats_api.timer('comment_client.request.time', tags=tags):
with dog_stats_api.timer('comment_client.request.time'):
if method in ['post', 'put', 'patch']:
response = requests.request(method, url, data=data_or_params, timeout=5)
else:
......
......@@ -36,3 +36,16 @@
@import 'news';
@import 'shame';
## THEMING
## -------
## Set up this file to import an edX theme library if the environment
## indicates that a theme should be used. The assumption is that the
## theme resides outside of this main edX repository, in a directory
## called themes/<theme-name>/, with its base Sass file in
## themes/<theme-name>/static/sass/_<theme-name>.scss. That one entry
## point can be used to @import in as many other things as needed.
% if not env['THEME_NAME'] is None:
// import theme's Sass overrides
@import '${env['THEME_NAME']}'
% endif
......@@ -8,7 +8,7 @@ from . import one_time_startup
import django.contrib.auth.views
# Uncomment the next two lines to enable the admin:
if settings.DEBUG:
if settings.DEBUG or settings.MITX_FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
admin.autodiscover()
urlpatterns = ('', # nopep8
......@@ -330,7 +330,7 @@ if settings.COURSEWARE_ENABLED:
if settings.ENABLE_JASMINE:
urlpatterns += (url(r'^_jasmine/', include('django_jasmine.urls')),)
if settings.DEBUG:
if settings.DEBUG or settings.MITX_FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
## Jasmine and admin
urlpatterns += (url(r'^admin/', include(admin.site.urls)),)
......
require 'json'
require 'rake/clean'
require './rakefiles/helpers.rb'
......@@ -7,6 +8,13 @@ end
# Build Constants
REPO_ROOT = File.dirname(__FILE__)
ENV_ROOT = File.dirname(REPO_ROOT)
REPORT_DIR = File.join(REPO_ROOT, "reports")
# Environment constants
SERVICE_VARIANT = ENV['SERVICE_VARIANT']
CONFIG_PREFIX = SERVICE_VARIANT ? SERVICE_VARIANT + "." : ""
ENV_FILE = File.join(ENV_ROOT, CONFIG_PREFIX + "env.json")
ENV_TOKENS = File.exists?(ENV_FILE) ? JSON.parse(File.read(ENV_FILE)) : {}
task :default => [:test, :pep8, :pylint]
# Theming constants
THEME_NAME = ENV_TOKENS['THEME_NAME']
USE_CUSTOM_THEME = !(THEME_NAME.nil? || THEME_NAME.empty?)
if USE_CUSTOM_THEME
THEME_ROOT = File.join(ENV_ROOT, "themes", THEME_NAME)
THEME_SASS = File.join(THEME_ROOT, "static", "sass")
end
# Run the specified file through the Mako templating engine, providing
# the ENV_TOKENS to the templating context.
def preprocess_with_mako(filename)
# simple command-line invocation of Mako engine
mako = "from mako.template import Template;" +
"print Template(filename=\"#{filename}\")" +
# Total hack. It works because a Python dict literal has
# the same format as a JSON object.
".render(env=#{ENV_TOKENS.to_json});"
# strip off the .mako extension
output_filename = filename.chomp(File.extname(filename))
# just pipe from stdout into the new file
File.open(output_filename, 'w') do |file|
file.write(`python -c '#{mako}'`)
end
end
def xmodule_cmd(watch=false, debug=false)
xmodule_cmd = 'xmodule_assets common/static/xmodule'
......@@ -32,10 +58,17 @@ def coffee_cmd(watch=false, debug=false)
end
def sass_cmd(watch=false, debug=false)
sass_load_paths = ["./common/static/sass"]
sass_watch_paths = ["*/static"]
if USE_CUSTOM_THEME
sass_load_paths << THEME_SASS
sass_watch_paths << THEME_SASS
end
"sass #{debug ? '--debug-info' : '--style compressed'} " +
"--load-path ./common/static/sass " +
"--load-path #{sass_load_paths.join(' ')} " +
"--require ./common/static/sass/bourbon/lib/bourbon.rb " +
"#{watch ? '--watch' : '--update'} */static"
"#{watch ? '--watch' : '--update'} #{sass_watch_paths.join(' ')}"
end
desc "Compile all assets"
......@@ -46,6 +79,13 @@ namespace :assets do
desc "Compile all assets in debug mode"
multitask :debug
desc "Preprocess all static assets that have the .mako extension"
task :preprocess do
# Run assets through the Mako templating engine. Right now we
# just hardcode the asset filenames.
preprocess_with_mako("lms/static/sass/application.scss.mako")
end
desc "Watch all assets for changes and automatically recompile"
task :watch => 'assets:_watch' do
puts "Press ENTER to terminate".red
......@@ -54,9 +94,9 @@ namespace :assets do
{:xmodule => :install_python_prereqs,
:coffee => :install_node_prereqs,
:sass => :install_ruby_prereqs}.each_pair do |asset_type, prereq_task|
:sass => [:install_ruby_prereqs, :preprocess]}.each_pair do |asset_type, prereq_tasks|
desc "Compile all #{asset_type} assets"
task asset_type => prereq_task do
task asset_type => prereq_tasks do
cmd = send(asset_type.to_s + "_cmd", watch=false, debug=false)
if cmd.kind_of?(Array)
cmd.each {|c| sh(c)}
......@@ -71,7 +111,7 @@ namespace :assets do
namespace asset_type do
desc "Compile all #{asset_type} assets in debug mode"
task :debug => prereq_task do
task :debug => prereq_tasks do
cmd = send(asset_type.to_s + "_cmd", watch=false, debug=true)
sh(cmd)
end
......@@ -82,7 +122,7 @@ namespace :assets do
$stdin.gets
end
task :_watch => prereq_task do
task :_watch => prereq_tasks do
cmd = send(asset_type.to_s + "_cmd", watch=true, debug=true)
if cmd.kind_of?(Array)
cmd.each {|c| background_process(c)}
......
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