Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions inginious/frontend/pages/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def show_page(self, course):
course_grade = course.get_task_dispenser().get_course_grade(username)

# Get tag list
tag_list = course.get_tags()
categories = set(course.get_task_dispenser().get_all_categories())

# Get user info
user_info = self.user_manager.get_user_info(username)
Expand All @@ -91,4 +91,4 @@ def show_page(self, course):
submissions=last_submissions,
tasks_data=tasks_data,
grade=course_grade,
tag_filter_list=tag_list)
category_filter_list=categories)
6 changes: 3 additions & 3 deletions inginious/frontend/pages/course_admin/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def GET_AUTH(self, courseid): # pylint: disable=arguments-differ
user_input["users"] = flask.request.args.getlist("users")
user_input["audiences"] = flask.request.args.getlist("audiences")
user_input["tasks"] = flask.request.args.getlist("tasks")
user_input["org_tags"] = flask.request.args.getlist("org_tags")
user_input["org_categories"] = flask.request.args.getlist("org_categories")
params = self.get_input_params(user_input, course, 500)

return self.page(course, params)
Expand All @@ -175,7 +175,7 @@ def POST_AUTH(self, courseid): # pylint: disable=arguments-differ
user_input["users"] = flask.request.form.getlist("users")
user_input["audiences"] = flask.request.form.getlist("audiences")
user_input["tasks"] = flask.request.form.getlist("tasks")
user_input["org_tags"] = flask.request.form.getlist("org_tags")
user_input["org_categories"] = flask.request.form.getlist("org_categories")
params = self.get_input_params(user_input, course, 500)

return self.page(course, params)
Expand All @@ -202,7 +202,7 @@ def page(self, course, params):
users, tutored_users, audiences, tutored_audiences, tasks, limit = self.get_course_params(course, params)

filter, best_submissions_list = self.get_submissions_filter(course, only_tasks=params["tasks"],
only_tasks_with_categories=params["org_tags"],
only_tasks_with_categories=params["org_categories"],
only_users=params["users"],
only_audiences=params["audiences"],
grade_between=[
Expand Down
6 changes: 3 additions & 3 deletions inginious/frontend/pages/course_admin/submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def POST_AUTH(self, courseid): # pylint: disable=arguments-differ
user_input["users"] = flask.request.form.getlist("users")
user_input["audiences"] = flask.request.form.getlist("audiences")
user_input["tasks"] = flask.request.form.getlist("tasks")
user_input["org_tags"] = flask.request.form.getlist("org_tasks")
user_input["org_categories"] = flask.request.form.getlist("org_categories")

if "replay_submission" in user_input:
# Replay a unique submission
Expand Down Expand Up @@ -91,7 +91,7 @@ def GET_AUTH(self, courseid): # pylint: disable=arguments-differ
user_input["users"] = flask.request.args.getlist("users")
user_input["audiences"] = flask.request.args.getlist("audiences")
user_input["tasks"] = flask.request.args.getlist("tasks")
user_input["org_tags"] = flask.request.args.getlist("org_tasks")
user_input["org_categories"] = flask.request.args.getlist("org_categories")

if "download_submission" in user_input:
submission = self.database.submissions.find_one({"_id": ObjectId(user_input["download_submission"]),
Expand Down Expand Up @@ -144,7 +144,7 @@ def submissions_from_user_input(self, course, user_input, msgs, page=None, limit
skip = (page-1) * limit

return self.get_selected_submissions(course, only_tasks=user_input["tasks"],
only_tasks_with_categories=user_input["org_tags"],
only_tasks_with_categories=user_input["org_categories"],
only_users=user_input["users"],
only_audiences=user_input["audiences"],
grade_between=[
Expand Down
7 changes: 0 additions & 7 deletions inginious/frontend/pages/course_admin/task_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,6 @@ def POST_AUTH(self, courseid, taskid): # pylint: disable=arguments-differ
data["problems"] = OrderedDict([(key, self.parse_problem(val))
for key, val in sorted(iter(problems.items()), key=lambda x: int(x[1]['@order']))])

# Categories
course_tags = course.get_tags()
data['categories'] = [cat for cat in map(str.strip, data['categories'].split(',')) if cat]
for category in data['categories']:
if category not in course_tags:
return json.dumps({"status": "error", "message": _("Unknown category tag.")})

# Task environment parameters
data["environment_parameters"] = environment_parameters

Expand Down
7 changes: 3 additions & 4 deletions inginious/frontend/pages/course_admin/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,8 @@ def get_input_params(self, user_input, course, limit=50):
# Sanitise tags
if not user_input.get("tasks", []):
user_input["tasks"] = []
if len(user_input.get("org_tags", [])) == 1 and "," in user_input["org_tags"][0]:
user_input["org_tags"] = user_input["org_tags"][0].split(',')
user_input["org_tags"] = [org_tag for org_tag in user_input["org_tags"] if org_tag in course.get_tags()]
if len(user_input.get("org_categories", [])) == 1 and "," in user_input["org_categories"][0]:
user_input["org_categories"] = user_input["org_categories"][0].split(',')

# Sanitise grade
if "grade_min" in user_input:
Expand Down Expand Up @@ -186,7 +185,7 @@ def get_submissions_filter(self, course,
elif only_tasks_with_categories:
only_tasks_with_categories = set(only_tasks_with_categories)
more_tasks = {taskid for taskid, task in course.get_tasks().items() if
only_tasks_with_categories.intersection(task.get_categories())}
only_tasks_with_categories.intersection(course.get_task_dispenser().get_categories(taskid))}
if only_tasks:
self._validate_list(only_tasks)
more_tasks.intersection_update(only_tasks)
Expand Down
5 changes: 2 additions & 3 deletions inginious/frontend/pages/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ def GET(self, courseid, taskid, is_LTI):

# Visible tags
course_tags = course.get_tags()
task_categories = task.get_categories()
visible_tags = [course_tags[category] for category in task_categories if
Comment thread
anthonygego marked this conversation as resolved.
course_tags[category].is_visible_for_student() or self.user_manager.has_staff_rights_on_course(course)]
visible_tags = [tags for _,tags in course_tags.items() if
tags.is_visible_for_student() or self.user_manager.has_staff_rights_on_course(course)]

# Problem dict
pdict = {problem.get_id(): problem.get_type() for problem in task.get_problems()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@
</div>

<div id="tags_of_task" style="display:none;">
{% for category in task.get_categories() %}
{% set tag = tag_list[category] %}
{% if tag.is_visible_for_student() or user_manager.has_staff_rights_on_course(course) %}
<div id="tag" data-tag-name="{{tag.get_id()}}"></div>
{% endif %}
{% for category in course.get_task_dispenser().get_categories(task.get_id()) %}
<div id="tag" data-tag-name="{{ category }}"></div>
{% endfor %}
</div>
</a>
Expand Down
1 change: 1 addition & 0 deletions inginious/frontend/static/js/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ function updateMainTags(data){
if(elem.attr('class') == "badge alert-danger"){
elem.show();
}else{
elem.show();
elem.attr('class', 'badge alert-success')
}
}
Expand Down
12 changes: 12 additions & 0 deletions inginious/frontend/static/js/task_dispensers.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ function dispenser_util_get_sections_list(element) {

structure["no_stored_submissions"] = dispenser_util_get_no_stored_submissions(tasks_id);
structure["evaluation_mode"] = dispenser_util_get_evaluation_mode(tasks_id);
structure["categories"] = dispenser_util_get_categories(tasks_id);
} else if ($(this).hasClass("sections_list")) {
structure["sections_list"] = dispenser_util_get_sections_list(content);
}
Expand Down Expand Up @@ -439,6 +440,17 @@ function dispenser_util_get_evaluation_mode(tasks_id){
return evaluation_mode;
}

function dispenser_util_get_categories(tasks_id){
const categories = {};
$(".categories").each(function(){
var taskid = this.id;
if(taskid in tasks_id && this.value !== ""){
categories[taskid] = this.value.split(",");
}
});
return categories;
}

function dispenser_util_get_tasks_list(element) {
const tasks_list = {};
element.children(".task").each(function (index) {
Expand Down
10 changes: 10 additions & 0 deletions inginious/frontend/task_dispensers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ def get_evaluation_mode(self, taskid):
"""Returns the evaluation mode specified by the administrator"""
pass

@abstractmethod
def get_categories(self,taskid):
"""Returns the categories specified for the taskid by the administrator"""
pass

@abstractmethod
def get_all_categories(self):
"""Returns the categories specified by the administrator"""
pass

@abstractmethod
def get_course_grade(self, username):
"""Returns the current grade of the course for a specific user"""
Expand Down
27 changes: 27 additions & 0 deletions inginious/frontend/task_dispensers/combinatory_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,33 @@ def get_evaluation_mode(self,taskid):
except:
return "best"

def get_categories(self,taskid):
"""Returns the categories specified for the taskid by the administrator"""
try:
struct = self._data.to_structure()
for elem in struct:
categories = self._data.get_value_rec(taskid,elem,"categories")
if categories is not None:
return categories
return []
except:
return []

def get_all_categories(self):
"""Returns the categories specified by the administrator"""
tasks = self._data.get_tasks()
all_categories = []
for task in tasks:
try:
struct = self._data.to_structure()
for elem in struct:
categories = self._data.get_value_rec(task,elem,"categories")
if categories is not None:
all_categories += categories
except:
return all_categories
return all_categories

def get_course_grade(self, username):
""" Returns the grade of a user for the current course"""
task_list = self.get_user_task_list([username])[username]
Expand Down
27 changes: 27 additions & 0 deletions inginious/frontend/task_dispensers/toc.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ def get_evaluation_mode(self,taskid):
except:
return "best"

def get_categories(self,taskid):
"""Returns the categories specified for the taskid by the administrator"""
try:
struct = self._toc.to_structure()
for elem in struct:
categories = self._toc.get_value_rec(taskid,elem,"categories")
if categories is not None:
return categories
return []
except:
return []

def get_all_categories(self):
"""Returns the categories specified by the administrator"""
tasks = self._toc.get_tasks()
all_categories = []
for task in tasks:
try:
struct = self._toc.to_structure()
for elem in struct:
categories = self._toc.get_value_rec(task,elem,"categories")
if categories is not None:
all_categories += categories
except:
return all_categories
return all_categories

def get_course_grade(self, username):
""" Returns the grade of a user for the current course"""
task_list = self.get_user_task_list([username])[username]
Expand Down
26 changes: 16 additions & 10 deletions inginious/frontend/task_dispensers/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,30 +206,34 @@ def __init__(self, structure):
for taskid,weight in structure["weights"].items():
if not (type(weight) == float or type(weight) == int):
raise InvalidTocException( ("The weight value must be a numeric >= 0 for the task: " + str(taskid)) )
elif weight >= 0:
elif weight < 0:
raise InvalidTocException( ("The weight value must be a numeric >= 0 for the task: " + str(taskid)) )
else:
if taskid in structure['tasks_list']:
self._weights[taskid] = weight
else:
raise InvalidTocException( ("The weight value must be a numeric >= 0 for the task: " + str(taskid)) )

self._no_stored_submissions = {}
if "no_stored_submissions" in structure:
for taskid,no_stored_submissions in structure["no_stored_submissions"].items():
if not type(no_stored_submissions) == int:
raise InvalidTocException( ("The store submission must be an integer > 1 for the task: " + str(taskid)) )
elif no_stored_submissions >= 0:
if taskid in structure['tasks_list']:
self._no_stored_submissions = structure["no_stored_submissions"]
else:
elif no_stored_submissions < 0:
raise InvalidTocException( ("The store submission must be an integer > 1 for the task: " + str(taskid)) )
self._no_stored_submissions = structure["no_stored_submissions"]

self._evaluation_mode = {}
if "evaluation_mode" in structure:
for taskid,evaluation_mode in structure["evaluation_mode"].items():
if evaluation_mode != "best" and evaluation_mode != "last":
raise InvalidTocException( ("The evaluation mode must be either best or last for the task: '" + str(taskid)) +"' but is " + str(evaluation_mode) )
else:
self._evaluation_mode = structure["evaluation_mode"]
self._evaluation_mode = structure["evaluation_mode"]

self._categories = {}
if "categories" in structure:
for taskid,categorie in structure["categories"].items():
if "" in categorie:
raise InvalidTocException( ("The categorie must have a name for the task: '" + str(taskid)) +"' but is " + str(categorie) )
self._categories = structure["categories"]

def is_terminal(self):
return True
Expand Down Expand Up @@ -273,7 +277,9 @@ def to_structure(self, rank):
:return: The structure in YAML format
"""
return {"id": self._id, "rank": rank, "title": self._title,
"tasks_list": {taskid: rank for rank, taskid in enumerate(self._task_list)}, "weights": self._weights, "no_stored_submissions": self._no_stored_submissions, "evaluation_mode": self._evaluation_mode}
"tasks_list": {taskid: rank for rank, taskid in enumerate(self._task_list)},
"weights": self._weights, "no_stored_submissions": self._no_stored_submissions,
"evaluation_mode": self._evaluation_mode, "categories": self._categories }


def check_toc(toc):
Expand Down
7 changes: 0 additions & 7 deletions inginious/frontend/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ def __init__(self, course, taskid, content, filesystem, plugin_manager, task_pro
# Regenerate input random
self._regenerate_input_random = bool(self._data.get("regenerate_input_random", False))

# Category tags
self._categories = self._data.get("categories", [])

def get_translation_obj(self, language):
return self._translations.get(language, gettext.NullTranslations())

Expand Down Expand Up @@ -239,10 +236,6 @@ def adapt_input_for_backend(self, input_data):
for problem in self._problems:
input_data = problem.adapt_input_for_backend(input_data)
return input_data

def get_categories(self):
""" Returns the tags id associated to the task """
return [category for category in self._categories if category in self._course.get_tags()]

def get_number_input_random(self):
""" Return the number of random inputs """
Expand Down
12 changes: 5 additions & 7 deletions inginious/frontend/templates/course.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,12 @@ <h3>{{ _("Enroll in the course") }}</h3>
<h2>{{ course.get_name(user_manager.session_language()) }}</h2>
</div>

{%if tag_filter_list %}
{%if category_filter_list %}
<div class="col-md-4 p-3">
<select class="form-control input-sm" style="height: 22px; padding: 2px 5px; font-size: 12px; line-height: 1.5;" id="tag_filter" onchange="filter_tag(this)">
<option value=""> {{ _("Filter tasks by tags") }}</option>
{% for key, tag in tag_filter_list.items() %}
{% if tag.get_type() in [0, 2] and tag.is_visible_for_student() %}
<option value="{{ tag.get_id() }}">{{ tag.get_name(user_manager.session_language()) }}</option>
{% endif %}
<option value=""> {{ _("Filter tasks by category") }}</option>
{% for category in category_filter_list %}
<option value="{{ category }}">{{ category }}</option>
{% endfor %}
</select>
</div>
Expand Down Expand Up @@ -175,7 +173,7 @@ <h2>{{ course.get_name(user_manager.session_language()) }}</h2>
}
</style>

{{ course.get_task_dispenser().render(template_helper, course, tasks_data, tag_filter_list) | safe }}
{{ course.get_task_dispenser().render(template_helper, course, tasks_data, category_filter_list) | safe }}

{% include "unregister_modal.html" %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@
<input type="text" class="form-control" id="contact-url" name="contact_url" placeholder="{{_('Contact link')}}" value="{{task_data.get('contact_url','')}}"/>
</div>
</div>
<div class="form-group row">
<label for="categories" class="col-sm-2 control-label">{{_("Categories")}}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="categories" name="categories" placeholder="{{ _('Tag ids, separated by commas') }}"
value="{{ task_data.get('categories', []) | join(',') }}">
</div>
</div>
<div class="form-group row">
<label for="groups" class="col-sm-2 control-label">{{_("Submission mode")}}</label>
<div class="col-sm-10">
Expand Down
2 changes: 0 additions & 2 deletions inginious/frontend/templates/course_admin/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ <h2>{{_("Course settings")}}</h2>
<select disabled class="form-control" name="tags[NEW][type]">
<option value="0" TYPE_REPLACE_0>{{_("Skill")}}</option>
<option value="1" TYPE_REPLACE_1>{{_("Misconception")}}</option>
<option value="2" TYPE_REPLACE_2>{{_("Category")}}</option>
</select>
</td>
</tr>
Expand All @@ -420,7 +419,6 @@ <h2>{{_("Course settings")}}</h2>
<select class="form-control" name="tags[{{loop.index}}][type]">
<option value="0" {% if type|int == 0 %} selected="selected" {% endif %}>{{_("Skill")}}</option>
<option value="1" {% if type|int == 1 %} selected="selected" {% endif %}>{{_("Misconception")}}</option>
<option value="2" {% if type|int == 2 %} selected="selected" {% endif %}>{{_("Category")}}</option>
</select>
</td>
</tr>
Expand Down
Loading