Add support for per-course site status.
Now looks for a status_message.json file, looks for 'global' and ${course.id} keys. Return any global message and any course-specific message, joined by <br>.
fab files need to be updated to use this new format (new filename, possibly also help manage per-course messages, or at least test for valid json)
This commit is contained in:
@@ -3,27 +3,41 @@ A tiny app that checks for a status message.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def get_site_status_msg():
|
||||
def get_site_status_msg(course):
|
||||
"""
|
||||
Look for a file settings.STATUS_MESSAGE_PATH. If found, return the
|
||||
contents. Otherwise, return None.
|
||||
Look for a file settings.STATUS_MESSAGE_PATH. If found, read it,
|
||||
parse as json, and do the following:
|
||||
|
||||
* if there is a key 'global', include that in the result list.
|
||||
* if course is not None, and there is a key for course.id, add that to the result list.
|
||||
* return "<br/>".join(result)
|
||||
|
||||
Otherwise, return None.
|
||||
|
||||
If something goes wrong, returns None. ("is there a status msg?" logic is
|
||||
not allowed to break the entire site).
|
||||
"""
|
||||
try:
|
||||
content = None
|
||||
if os.path.isfile(settings.STATUS_MESSAGE_PATH):
|
||||
with open(settings.STATUS_MESSAGE_PATH) as f:
|
||||
content = f.read()
|
||||
else:
|
||||
return None
|
||||
|
||||
return content
|
||||
status_dict = json.loads(content)
|
||||
msg = status_dict.get('global', None)
|
||||
if course and course.id in status_dict:
|
||||
msg = msg + "<br>" if msg else ''
|
||||
msg += status_dict[course.id]
|
||||
|
||||
return msg
|
||||
except:
|
||||
log.exception("Error while getting a status message.")
|
||||
return None
|
||||
|
||||
91
common/djangoapps/status/tests.py
Normal file
91
common/djangoapps/status/tests.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from tempfile import NamedTemporaryFile
|
||||
import os
|
||||
from override_settings import override_settings
|
||||
|
||||
from status import get_site_status_msg
|
||||
|
||||
import xmodule.modulestore.django
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.xml_importer import import_from_xml
|
||||
|
||||
|
||||
class TestStatus(TestCase):
|
||||
"""Test that the get_site_status_msg function does the right thing"""
|
||||
|
||||
no_file = None
|
||||
|
||||
invalid_json = """{
|
||||
"global" : "Hello, Globe",
|
||||
}"""
|
||||
|
||||
global_only = """{
|
||||
"global" : "Hello, Globe"
|
||||
}"""
|
||||
|
||||
toy_only = """{
|
||||
"edX/toy/2012_Fall" : "A toy story"
|
||||
}"""
|
||||
|
||||
global_and_toy = """{
|
||||
"global" : "Hello, Globe",
|
||||
"edX/toy/2012_Fall" : "A toy story"
|
||||
}"""
|
||||
|
||||
|
||||
# json to use, expected results for course=None (e.g. homepage),
|
||||
# for toy course, for full course. Note that get_site_status_msg
|
||||
# is supposed to return global message even if course=None. The
|
||||
# template just happens to not display it outside the courseware
|
||||
# at the moment...
|
||||
checks = [
|
||||
(no_file, None, None, None),
|
||||
(invalid_json, None, None, None),
|
||||
(global_only, "Hello, Globe", "Hello, Globe", "Hello, Globe"),
|
||||
(toy_only, None, "A toy story", None),
|
||||
(global_and_toy, "Hello, Globe", "Hello, Globe<br>A toy story", "Hello, Globe"),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
xmodule.modulestore.django._MODULESTORES = {}
|
||||
courses = modulestore().get_courses()
|
||||
|
||||
def find_course(course_id):
|
||||
"""Assumes the course is present"""
|
||||
return [c for c in courses if c.id==course_id][0]
|
||||
|
||||
self.full = find_course("edX/full/6.002_Spring_2012")
|
||||
self.toy = find_course("edX/toy/2012_Fall")
|
||||
|
||||
def create_status_file(self, contents):
|
||||
"""
|
||||
Write contents to settings.STATUS_MESSAGE_PATH.
|
||||
"""
|
||||
with open(settings.STATUS_MESSAGE_PATH, 'w') as f:
|
||||
f.write(contents)
|
||||
|
||||
def remove_status_file(self):
|
||||
"""Delete the status file if it exists"""
|
||||
if os.path.exists(settings.STATUS_MESSAGE_PATH):
|
||||
os.remove(settings.STATUS_MESSAGE_PATH)
|
||||
|
||||
def tearDown(self):
|
||||
self.remove_status_file()
|
||||
|
||||
def test_get_site_status_msg(self):
|
||||
"""run the tests"""
|
||||
for (json_str, exp_none, exp_toy, exp_full) in self.checks:
|
||||
|
||||
self.remove_status_file()
|
||||
if json_str:
|
||||
self.create_status_file(json_str)
|
||||
|
||||
print "checking results for {0}".format(json_str)
|
||||
print "course=None:"
|
||||
self.assertEqual(get_site_status_msg(None), exp_none)
|
||||
print "course=toy:"
|
||||
self.assertEqual(get_site_status_msg(self.toy), exp_toy)
|
||||
print "course=full:"
|
||||
self.assertEqual(get_site_status_msg(self.full), exp_full)
|
||||
@@ -129,7 +129,7 @@ NODE_PATH = ':'.join(node_paths)
|
||||
|
||||
|
||||
# Where to look for a status message
|
||||
STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.html"
|
||||
STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json"
|
||||
|
||||
############################ OpenID Provider ##################################
|
||||
OPENID_PROVIDER_TRUSTED_ROOTS = ['cs50.net', '*.cs50.net']
|
||||
|
||||
@@ -40,6 +40,8 @@ TEST_ROOT = path("test_root")
|
||||
# Want static files in the same dir for running on jenkins.
|
||||
STATIC_ROOT = TEST_ROOT / "staticfiles"
|
||||
|
||||
STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json"
|
||||
|
||||
COURSES_ROOT = TEST_ROOT / "data"
|
||||
DATA_DIR = COURSES_ROOT
|
||||
|
||||
@@ -77,6 +79,19 @@ STATICFILES_DIRS += [
|
||||
if os.path.isdir(COMMON_TEST_DATA_ROOT / course_dir)
|
||||
]
|
||||
|
||||
# point tests at the test courses by default
|
||||
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore',
|
||||
'OPTIONS': {
|
||||
'data_dir': COMMON_TEST_DATA_ROOT,
|
||||
'default_class': 'xmodule.hidden_module.HiddenDescriptor',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
|
||||
@@ -14,7 +14,12 @@ from status.status import get_site_status_msg
|
||||
|
||||
<%block cached="False">
|
||||
<%
|
||||
site_status_msg = get_site_status_msg()
|
||||
try:
|
||||
c = course
|
||||
except:
|
||||
# can't figure out a better way to get at a possibly-defined course var
|
||||
c = None
|
||||
site_status_msg = get_site_status_msg(c)
|
||||
%>
|
||||
% if site_status_msg:
|
||||
<div class="site-status">
|
||||
|
||||
Reference in New Issue
Block a user