-
Notifications
You must be signed in to change notification settings - Fork 303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
central-develop into 0.17.x #5595
Changes from 132 commits
95ae21e
0615773
3daac46
30758b4
5d6a29d
6d7e510
0cef1b9
6c70ea7
8fea95e
318a01a
bf146dc
c6402d3
c1abb70
5105876
6e6c0f0
26592ee
61fb56b
5286833
af8d016
350a7f5
1c582c2
66a0248
c106ca1
8e5e8e5
bc21a36
3bffde5
5e0b016
d4c91a2
cfb423d
14c8701
b56a514
4ffdb35
7c9085b
b68aadf
618314d
2c5cce4
b3f28a0
c06bab5
dd65adb
0299599
e890a2d
b289d0f
54c23cb
1509abc
0597547
a6d62e5
6e8da48
6177f63
ee90bd5
a5a5b1b
3bbd98e
abb207c
e6f34b2
1f19654
2ebd3ed
097a747
073046f
105272d
e1d6c23
63824f6
f13286c
c29c18d
645c7f0
1648ace
3755b72
d24b7ab
05bf1cd
3aaeea8
5f82a77
99dbcdb
c12f0ce
a276b0c
8a4d4be
f0bd27c
34a27be
65330fb
eb670d5
8ffa4d2
ea857a6
3ae33e7
3510566
3d273f2
ab8bc62
263e52b
b0a9d48
83006de
a253c1b
c3cc5ef
626f915
9801731
452e19e
4d408f3
4771c3c
171f2f7
1c49921
de616c3
c682fa4
5942943
259d8ae
cabc30f
2a5fa54
590752e
1f87909
8adb6f3
68c6ffe
30f8bd1
6f62e04
41923fc
d6abcae
0c49a77
fbc2912
c01942e
719921a
361834b
1323db0
cd4cb41
e418511
4951c10
90d20c6
d7cdc84
dc56afc
c789b22
bf2cfa4
cb25c26
45cc3e4
a118a2d
bdf518c
635c5ea
a2b59b0
3555f82
9272dcf
3fccd47
a56efba
54bc417
650a95d
e554397
338fc49
f2ae87c
5161c9b
bc367a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
.selection { | ||
float: left; | ||
padding: 0 10px 10px 0; | ||
} | ||
|
||
#displaygrid { | ||
width: 100%; | ||
padding-top: 5px; | ||
padding-left: 2px; | ||
} | ||
|
||
#displaygrid > .users { | ||
width: 11%; | ||
margin-right: 1px; | ||
float: left; | ||
} | ||
|
||
.userstatus { | ||
overflow: auto; | ||
width: 88%; | ||
} | ||
|
||
.users table { | ||
width: 100%; | ||
} | ||
|
||
#displaygrid table { | ||
table-layout: fixed; | ||
} | ||
|
||
th, td { | ||
border: 1px solid black; | ||
padding: 2px; | ||
vertical-align:middle; | ||
} | ||
|
||
.users th { | ||
text-align: left; | ||
} | ||
|
||
.subtitle { | ||
font-size: 1.15em; | ||
font-weight: bold; | ||
} | ||
|
||
.status { | ||
height: 27px; | ||
background-color: #EEE; | ||
} | ||
|
||
th.username { | ||
height: 27px; | ||
border: 1px solid black; | ||
padding-left: 5px; | ||
white-space: nowrap; | ||
text-overflow: ellipsis; | ||
} | ||
|
||
th.headrow, th.headrow div { | ||
width: 80px; | ||
font-weight: bold; | ||
background-color: white; | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
} | ||
|
||
th.headrowuser { | ||
font-weight: bold; | ||
} | ||
|
||
.complete { | ||
background-color: #2F942F; | ||
} | ||
|
||
.partial { | ||
background-color: #94BE48; | ||
} | ||
|
||
.struggle { | ||
background-color: #CA4D4D; | ||
} | ||
|
||
#displaygrid td, #displaygrid th { | ||
min-width: 60px; | ||
max-width: 60px; | ||
overflow: hidden; | ||
} | ||
|
||
#legend a { | ||
height:12px; | ||
margin:0px; | ||
padding:0px; | ||
} | ||
|
||
.student-name, .attempts, .streak_progress, .points, .total_seconds_watched { | ||
float:left; | ||
display:none; | ||
overflow:hidden; | ||
white-space:nowrap; | ||
width:100%; | ||
margin:0px 5px 0px 0px; | ||
padding:0px; | ||
text-align:right; | ||
vertical-align:middle; | ||
} | ||
|
||
.student-name { | ||
float:none; | ||
text-align:left; | ||
display:block; | ||
text-overflow: ellipsis; | ||
} | ||
|
||
#legend { | ||
float:left; | ||
vertical-align:middle; | ||
margin:12px 25px 2px 10px; | ||
} | ||
|
||
.legend { | ||
float:right; | ||
width:160px; | ||
height:20px; | ||
text-align:center; | ||
vertical-align:middle; | ||
white-space:nowrap; | ||
overflow:hidden; | ||
border-style:solid; | ||
border-width: 1px; | ||
padding:2px; | ||
margin-right: 10px; | ||
font-weight: bold; | ||
} | ||
|
||
.legend div { | ||
float:left; | ||
width:35px; | ||
height:21px; | ||
} | ||
|
||
#selection-bar { | ||
overflow:hide; | ||
} | ||
|
||
#disp_options { | ||
float:right; | ||
} | ||
|
||
.exercise-name { | ||
height: 100px; | ||
text-align: center; | ||
vertical-align: none; | ||
padding: 0px; | ||
} | ||
|
||
#exercise-mastery { | ||
font-size: 10px | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
$(function() { | ||
|
||
$("#student").change(function() { | ||
window.location.href = setGetParam(window.location.href, "user", $("#student option:selected").val()); | ||
}); | ||
|
||
$("#playlist").change(function() { | ||
window.location.href = setGetParam(window.location.href, "playlist", $("#playlist option:selected").val()); | ||
}); | ||
|
||
$("#facility").change(function() { | ||
window.location.href = setGetParamDict(window.location.href, { | ||
"facility": $("#facility option:selected").val(), | ||
"group": $("#" + $("#facility option:selected").val() + "_group_select").val(), | ||
"playlist": "" | ||
}); | ||
}); | ||
|
||
$(".group_select").change(function(event) { | ||
window.location.href = setGetParam(window.location.href, "group", $(event.target).val()); | ||
}); | ||
|
||
// Selector to toggle visible elements is stored in each option value | ||
cell_height = 27; | ||
$("#disp_options").change(function() { | ||
selector = $("#disp_options option:selected").val(); | ||
|
||
// adjust the cell height | ||
cell_height += 50 * Math.pow(-1, 0 + $(selector).is(":visible")); | ||
|
||
// adjust view in data cells | ||
$(selector).each(function() { | ||
$(this).toggle(); | ||
}); | ||
$(selector).each(function() { | ||
$(this).height(20); | ||
$(this).parent().height(cell_height); | ||
}); | ||
|
||
// Adjust student name cell heights | ||
$("th.username").each(function() { | ||
$(this).height(cell_height); | ||
}); | ||
}); | ||
$(window).resize(function() { | ||
$('.headrowuser').height($('.headrow.data').height()); | ||
}).resize(); | ||
}); | ||
|
||
$(function(){ | ||
$("#tree").dynatree({ | ||
persist: true, | ||
expand: false, | ||
checkbox: true, | ||
selectMode: 3, | ||
cookieId: "exercises", | ||
children: null, | ||
|
||
onPostInit: function(isReloading, isError) { | ||
if (window.location.href.indexOf("&playlist=") == -1) { | ||
$("#tree").dynatree("getTree").visit(function(node){ | ||
node.select(false); | ||
node.expand(false); | ||
}); | ||
} | ||
}, | ||
onSelect: function(select, dtnode) { | ||
var selKeys = $.map(dtnode.tree.getSelectedNodes(), function(dtnode){ | ||
return dtnode.data.key; | ||
}); | ||
window.location.href = setGetParam(window.location.href, "playlist", selKeys); | ||
} | ||
}); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be a feature lost from 0.16.x - or it might be unwanted in 0.17? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The two @aronasorman noted:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CSS lives here: I've searched the codebase for occurrences of "exercise_mastery_view", and as there are none, I will assume that the JS file is unused. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,6 +282,23 @@ def alter_list_data_to_serialize(self, request, to_be_serialized): | |
attempt_logs = AttemptLog.objects.filter(user=user, exercise_id=bundle.data["exercise_id"], context_type__in=["playlist", "exercise"]) | ||
bundle.data["timestamp_first"] = attempt_logs.count() and attempt_logs.aggregate(Min('timestamp'))['timestamp__min'] or None | ||
bundle.data["timestamp_last"] = attempt_logs.count() and attempt_logs.aggregate(Max('timestamp'))['timestamp__max'] or None | ||
bundle.data["unit"] = 0 | ||
|
||
# Anything done after Nov 15, 2014 is in the RCT which starts from Unit 101 | ||
if StoreTransactionLog.objects.filter(user=user, context_type="unit_points_reset", purchased_at__gte=datetime(2014, 11, 15, 0, 0, 0)).count() == 0: | ||
bundle.data["unit"] = 101 | ||
|
||
elif bundle.data["timestamp_first"]: | ||
for i in xrange(101,104): | ||
if StoreTransactionLog.objects.filter(user=user, context_id=i, context_type="unit_points_reset", purchased_at__gte=bundle.data["timestamp_first"]).count() > 0: | ||
bundle.data["unit"] = i | ||
break | ||
|
||
# For entries we are not sure about the unit, we keep them as 0, mostly chances are that the unit would be the current_unit. | ||
# As we can't predict the current unit on the central server, its better to have the value as 0. | ||
# We can't predict the current unit because in some database we have unit_point_reset gift card for unit 101 whereas the current unit is also 101. | ||
# So we can't find current_unit by saying that the first unit that doesn't have the unit_point_reset gift card is current_unit. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what all this is. Never heard about the "gift card" part nor the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
bundle.data["part1_answered"] = AttemptLog.objects.filter(user=user, exercise_id=bundle.data["exercise_id"], context_type__in=["playlist", "exercise"]).count() | ||
bundle.data["part1_correct"] = AttemptLog.objects.filter(user=user, exercise_id=bundle.data["exercise_id"], correct=True, context_type__in=["playlist", "exercise"]).count() | ||
bundle.data["part2_attempted"] = AttemptLog.objects.filter(user=user, exercise_id=bundle.data["exercise_id"], context_type__in=["exercise_fixedblock", "playlist_fixedblock"]).count() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,9 @@ require("browsernizr/test/canvas"); | |
require("browsernizr/test/touchevents"); | ||
var Modernizr = require("browsernizr"); | ||
|
||
// Expose this as a global object for use in central server inline JS. | ||
global.getCookie = require("utils/get_cookie"); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be configurable and only switched on in the central server. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, this might actually be harmless to the rest of the KA Lite application, wouldn't you think so @rtibbles ? |
||
global.$ = $; | ||
global._ = _; | ||
global.sessionModel = new SessionModel(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,6 +118,73 @@ def call_command_async(cmd, *args, **kwargs): | |
return call_command_subprocess(cmd, *args, **kwargs) | ||
|
||
|
||
def call_outside_command_with_output(command, *args, **kwargs): | ||
""" | ||
Runs call_command for a KA Lite installation at the given location, | ||
and returns the output. | ||
""" | ||
|
||
if settings.IS_SOURCE: | ||
assert "kalite_dir" in kwargs, "don't forget to specify the kalite_dir" | ||
kalite_dir = kwargs.pop('kalite_dir') | ||
else: | ||
kalite_dir = None | ||
|
||
# some custom variables that have to be put inside kwargs | ||
# or else will mess up the way the command is called | ||
output_to_stdout = kwargs.pop('output_to_stdout', False) | ||
output_to_stderr = kwargs.pop('output_to_stderr', False) | ||
wait = kwargs.pop('wait', True) | ||
|
||
# build the command | ||
if kalite_dir: | ||
kalite_bin = os.path.join(kalite_dir, "bin", "kalite") | ||
else: | ||
kalite_bin = 'kalite' | ||
|
||
cmd = (kalite_bin, "manage", command) if os.name != "nt" else (sys.executable, kalite_bin, "manage", command) | ||
for arg in args: | ||
cmd += (arg,) | ||
|
||
kwargs_keys = kwargs.keys() | ||
|
||
# Ensure --settings occurs first, as otherwise docopt parsing barfs | ||
kwargs_keys = sorted(kwargs_keys, cmp=lambda x,y: -1 if x=="settings" else 0) | ||
|
||
for key in kwargs_keys: | ||
val = kwargs[key] | ||
key = key.replace(u"_",u"-") | ||
prefix = u"--" if command != "runcherrypyserver" else u"" # hack, but ... whatever! | ||
if isinstance(val, bool): | ||
cmd += (u"%s%s" % (prefix, key),) | ||
else: | ||
# TODO(jamalex): remove this replacement, after #4066 is fixed: | ||
# https://github.com/learningequality/ka-lite/issues/4066 | ||
cleaned_val = unicode(val).replace(" ", "") | ||
cmd += (u"%s%s=%s" % (prefix, key, cleaned_val),) | ||
|
||
# we also need to change the environment to point to the the local | ||
# kalite settings. This is especially important for when the | ||
# central server calls this function, as if we don't change this, | ||
# kalitectl.py wil look for centralserver.settings instead of | ||
# kalite.settings. | ||
new_env = os.environ.copy() | ||
new_env["DJANGO_SETTINGS_MODULE"] = kwargs.get("settings") or "kalite.settings" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should ideally be configurable and only switched on in the central server. The whole function is only used in a test, though, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since all this code is used from the central server's test suite, I'm moving it there. |
||
|
||
p = subprocess.Popen( | ||
cmd, | ||
shell=False, | ||
# cwd=os.path.split(cmd[0])[0], | ||
stdout=None if output_to_stdout else subprocess.PIPE, | ||
stderr=None if output_to_stderr else subprocess.PIPE, | ||
env=new_env, | ||
) | ||
out = p.communicate() if wait else (None, None) | ||
|
||
# tuple output of stdout, stderr, exit code and process object | ||
return out + (1 if out[1] else 0, p) | ||
|
||
|
||
class LocaleAwareCommand(BaseCommand): | ||
option_list = BaseCommand.option_list + ( | ||
make_option('--locale', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a feature lost from 0.16.x - or it might be unwanted in 0.17?