diff --git a/cms/grading/languagemanager.py b/cms/grading/languagemanager.py index 097dc0adc2..9bc8c917d5 100644 --- a/cms/grading/languagemanager.py +++ b/cms/grading/languagemanager.py @@ -18,10 +18,10 @@ """Provide utilities to work with programming language classes.""" +import logging from cms import plugin_list from cms.grading.language import Language - __all__ = [ "LANGUAGES", "HEADER_EXTS", "SOURCE_EXTS", "OBJECT_EXTS", @@ -29,6 +29,9 @@ ] +logger = logging.getLogger(__name__) + + LANGUAGES: list[Language] = list() _BY_NAME: dict[str, Language] = dict() HEADER_EXTS: set[str] = set() @@ -50,6 +53,25 @@ def get_language(name: str) -> Language: return _BY_NAME[name] +def safe_get_lang_filename(lang: str | None, filename: str) -> str: + """Get the filename of a file in a specific programming language, + avoiding errors if the language isn't recognized. + + lang: name of the programming language + filename: filename template (containing .%l) + return: filename with the template replaced. + """ + if lang is None: + return filename + try: + language = get_language(lang) + source_ext = language.source_extension + except KeyError: + logger.warning(f"Found invalid language {lang}!") + source_ext = ".invalid_language" + return filename.replace(".%l", source_ext) + + def filename_to_language(filename: str, available_languages: list[Language] | None=None) -> Language | None: """Return one of the languages inferred from the given filename. diff --git a/cms/server/admin/handlers/submission.py b/cms/server/admin/handlers/submission.py index 2a062c7802..cd528cff1b 100644 --- a/cms/server/admin/handlers/submission.py +++ b/cms/server/admin/handlers/submission.py @@ -31,7 +31,7 @@ import difflib from cms.db import Dataset, File, Submission -from cms.grading.languagemanager import get_language +from cms.grading.languagemanager import safe_get_lang_filename from cmscommon.datetime import make_datetime from .base import BaseHandler, FileHandler, require_permission @@ -80,10 +80,7 @@ def get(self, file_id): sub_file = self.safe_get_item(File, file_id) submission = sub_file.submission - real_filename = sub_file.filename - if submission.language is not None: - real_filename = real_filename.replace( - ".%l", get_language(submission.language).source_extension) + real_filename = safe_get_lang_filename(submission.language, sub_file.filename) digest = sub_file.digest self.sql_session.close() @@ -130,10 +127,9 @@ def get(self, old_id, new_id): for fname in files_to_compare: if ".%l" in fname: if sub_old.language == sub_new.language and sub_old.language is not None: - ext = get_language(sub_old.language).source_extension + real_fname = safe_get_lang_filename(sub_old.language, fname) else: - ext = ".txt" - real_fname = fname.replace(".%l", ext) + real_fname = fname.replace(".%l", ".txt") else: real_fname = fname diff --git a/cms/server/admin/handlers/usertest.py b/cms/server/admin/handlers/usertest.py index 9a6cdfdd54..25328ed049 100644 --- a/cms/server/admin/handlers/usertest.py +++ b/cms/server/admin/handlers/usertest.py @@ -21,7 +21,7 @@ """ from cms.db import Dataset, UserTestFile, UserTest -from cms.grading.languagemanager import get_language +from cms.grading.languagemanager import safe_get_lang_filename from .base import BaseHandler, FileHandler, require_permission @@ -60,10 +60,7 @@ def get(self, file_id): user_test_file = self.safe_get_item(UserTestFile, file_id) user_test = user_test_file.user_test - real_filename = user_test_file.filename - if user_test.language is not None: - real_filename = real_filename.replace( - ".%l", get_language(user_test.language).source_extension) + real_filename = safe_get_lang_filename(user_test.language, user_test_file.filename) digest = user_test_file.digest self.sql_session.close() diff --git a/cms/server/admin/templates/fragments/user_test_row.html b/cms/server/admin/templates/fragments/user_test_row.html index e3d24146a5..b4fac30e7f 100644 --- a/cms/server/admin/templates/fragments/user_test_row.html +++ b/cms/server/admin/templates/fragments/user_test_row.html @@ -52,7 +52,7 @@

Compilation output

{# TODO: trim long outputs and add facility to see ra {% for filename, sub_file in ut.files|dictsort(by="key") %} - {% set real_filename = filename if ut.language is none else filename|replace(".%l", (ut.language|to_language).source_extension) %} + {% set real_filename = get_lang_filename(ut.language, filename) %} {{ real_filename }}
{% endfor %} diff --git a/cms/server/admin/templates/macro/submission.html b/cms/server/admin/templates/macro/submission.html index c6ee593137..0aec2850d9 100644 --- a/cms/server/admin/templates/macro/submission.html +++ b/cms/server/admin/templates/macro/submission.html @@ -165,7 +165,7 @@

Compilation output

{# TODO: trim long outputs and add facility to see ra {% for filename, sub_file in s.files|dictsort(by="key") %} - {% set real_filename = filename if s.language is none else filename|replace(".%l", (s.language|to_language).source_extension) %} + {% set real_filename = get_lang_filename(s.language, filename) %} {{ real_filename }}
{% endfor %} diff --git a/cms/server/admin/templates/submission.html b/cms/server/admin/templates/submission.html index d00f72567c..be25b02fde 100644 --- a/cms/server/admin/templates/submission.html +++ b/cms/server/admin/templates/submission.html @@ -48,7 +48,7 @@

Submission details

{% for filename in s.task.submission_format %} {% if filename in s.files %} - {% set real_filename = filename if s.language is none else filename|replace(".%l", (s.language|to_language).source_extension) %} + {% set real_filename = get_lang_filename(s.language, filename) %} {{ real_filename }} @@ -234,10 +234,14 @@

Evaluation (as seen by the us
- {% if s.tokened() %} - {{ st.get_html_details(sr.score_details, s.task.feedback_level)|safe }} + {% if st is defined %} + {% if s.tokened() %} + {{ st.get_html_details(sr.score_details, s.task.feedback_level)|safe }} + {% else %} + {{ st.get_html_details(sr.public_score_details, s.task.feedback_level)|safe }} + {% endif %} {% else %} - {{ st.get_html_details(sr.public_score_details, s.task.feedback_level)|safe }} + [Cannot get score type - see logs] {% endif %}
diff --git a/cms/server/admin/templates/user_test.html b/cms/server/admin/templates/user_test.html index 8fb1f86ea0..60d5213575 100644 --- a/cms/server/admin/templates/user_test.html +++ b/cms/server/admin/templates/user_test.html @@ -41,7 +41,7 @@

User test details

{% for filename in ut.task.submission_format %} {% if filename in ut.files %} - {% set real_filename = filename if ut.language is none else filename|replace(".%l", (ut.language|to_language).source_extension) %} + {% set real_filename = get_lang_filename(ut.language, filename) %} {{ real_filename }} diff --git a/cms/server/jinja2_toolbox.py b/cms/server/jinja2_toolbox.py index 4bfd9af245..0440b046bc 100644 --- a/cms/server/jinja2_toolbox.py +++ b/cms/server/jinja2_toolbox.py @@ -37,7 +37,7 @@ from cms.db import SubmissionResult, UserTestResult from cms.db.task import Dataset from cms.grading import format_status_text -from cms.grading.languagemanager import get_language +from cms.grading.languagemanager import get_language, safe_get_lang_filename from cms.locale import Translation, DEFAULT_TRANSLATION from cmscommon.constants import \ SCORE_MODE_MAX, SCORE_MODE_MAX_SUBTASK, SCORE_MODE_MAX_TOKENED_LAST @@ -204,10 +204,10 @@ def safe_get_score_type(env: Environment, *, dataset: Dataset): except Exception as err: return env.undefined("ScoreType not found: %s" % err) - def instrument_cms_toolbox(env: Environment): env.globals["get_task_type"] = safe_get_task_type env.globals["get_score_type"] = safe_get_score_type + env.globals["get_lang_filename"] = safe_get_lang_filename env.globals["get_mimetype_for_file_name"] = get_type_for_file_name env.globals["get_icon_for_mimetype"] = get_icon_for_type