From e2d7421b2fd76734805ebffa208fcb33b199276b Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 16:44:29 +0200 Subject: [PATCH 01/29] Add ProblemEditorial class like ProblemStatement class. --- oioioi/problems/models.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/oioioi/problems/models.py b/oioioi/problems/models.py index 0f3687eb6..ae4c9c3a0 100644 --- a/oioioi/problems/models.py +++ b/oioioi/problems/models.py @@ -257,6 +257,40 @@ def __str__(self): return '%s / %s' % (self.problem.name, self.filename) +class ProblemEditorial(models.Model): + """Represents a file containing problem editoral. + + Problem may have multiple editorials, for example in various languages + or formats. + """ + + problem = models.ForeignKey( + Problem, related_name='editorials', on_delete=models.CASCADE + ) + language = models.CharField( + max_length=6, blank=True, null=True, verbose_name=_("language code") + ) + content = FileField(upload_to=make_problem_filename, verbose_name=_("content")) + + @property + def filename(self): + return os.path.split(self.content.name)[1] + + @property + def download_name(self): + return self.problem.short_name + self.extension + + @property + def extension(self): + return os.path.splitext(self.content.name)[1].lower() + + class Meta(object): + verbose_name = _("problem editorial") + verbose_name_plural = _("problem editorials") + + def __str__(self): + return '%s / %s' % (self.problem.name, self.filename) + class ProblemAttachment(models.Model): """Represents an additional file visible to the contestant, linked to From 9266f73bb805514ce16624f69d9fd5d3a0c2a5da Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 17:16:25 +0200 Subject: [PATCH 02/29] Add initial, stupid editorial tab implementation. --- oioioi/problems/problem_site.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 9e9be53e8..e33d01a4f 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -34,6 +34,7 @@ ProblemAttachment, ProblemPackage, ProblemStatement, + ProblemEditorial, ) from oioioi.problems.problem_sources import UploadedPackageSource from oioioi.problems.utils import ( @@ -308,6 +309,29 @@ def problem_site_add_to_contest(request, problem): ) +def show_editorial(request, problem): + """Show Editorial tab only if there's ≥1 ProblemEditorial.""" + return ProblemEditorial.objects.filter(problem=problem).exists() and not request.contest + +@problem_site_tab( + _("Editorial"), + key='editorial', + order=750, + condition=show_editorial, +) +def problem_site_editorial(request, problem): + editorial = ProblemEditorial.objects.filter(problem=problem).order_by('language', 'id').first() + return TemplateResponse( + request, + 'problems/editorial.html', + { + 'problem': problem, + 'editorial': editorial, + 'can_admin_problem': can_admin_problem(request, problem), + } + ) + + @problem_site_tab( _("Replace problem statement"), key='replace_problem_statement', From af79e581fd203a0ac05d4ee585e2913d85bb2ee5 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 17:34:53 +0200 Subject: [PATCH 03/29] Abstract away query_statement contents into query_document and call it in query_statement and query_editorial. --- oioioi/problems/utils.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/oioioi/problems/utils.py b/oioioi/problems/utils.py index 3f7fd17fc..088e944cb 100644 --- a/oioioi/problems/utils.py +++ b/oioioi/problems/utils.py @@ -20,6 +20,7 @@ from oioioi.problems.models import ( AlgorithmTagProposal, DifficultyTagProposal, + ProblemEditorial, ProblemStatement, ProblemStatistics, UserStatistics, @@ -131,9 +132,8 @@ def can_add_to_problemset(request): return request.user.has_perm('problems.problems_db_admin') -def query_statement(problem_id): - statements = ProblemStatement.objects.filter(problem=problem_id) - if not statements: +def query_document(documents): + if not documents: return None lang_prefs = ( @@ -152,7 +152,15 @@ def sort_key(statement): ext_pref = (sys.maxsize, statement.extension) return lang_pref, ext_pref - return sorted(statements, key=sort_key)[0] + return sorted(documents, key=sort_key)[0] + +def query_statement(problem_id): + statements = ProblemStatement.objects.filter(problem=problem_id) + return query_document(statements) + +def query_editorial(problem_id): + editorials = ProblemEditorial.objects.filter(problem=problem_id) + return query_document(editorials) def query_zip(statement, path): From 1d737b915fd0bb82d4dd374660a0547d23e4a9da Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 17:41:45 +0200 Subject: [PATCH 04/29] Move editorial tab closer to statement. --- oioioi/problems/problem_site.py | 43 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index e33d01a4f..b9ff477c2 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -129,6 +129,26 @@ def problem_site_statement(request, problem): return statement_html +def show_editorial(request, problem): + """Show Editorial tab only if there's ≥1 ProblemEditorial.""" + return ProblemEditorial.objects.filter(problem=problem).exists() and not request.contest + +@problem_site_tab( + _("Editorial"), key='editorial', order=750, condition=show_editorial +) +def problem_site_editorial(request, problem): + editorial = ProblemEditorial.objects.filter(problem=problem).order_by('language', 'id').first() + return TemplateResponse( + request, + 'problems/editorial.html', + { + 'problem': problem, + 'editorial': editorial, + 'can_admin_problem': can_admin_problem(request, problem), + } + ) + + def check_for_downloads(request, problem): """Function checking if given problem has any downloadables.""" return bool(ProblemAttachment.objects.filter(problem=problem)) or bool( @@ -309,29 +329,6 @@ def problem_site_add_to_contest(request, problem): ) -def show_editorial(request, problem): - """Show Editorial tab only if there's ≥1 ProblemEditorial.""" - return ProblemEditorial.objects.filter(problem=problem).exists() and not request.contest - -@problem_site_tab( - _("Editorial"), - key='editorial', - order=750, - condition=show_editorial, -) -def problem_site_editorial(request, problem): - editorial = ProblemEditorial.objects.filter(problem=problem).order_by('language', 'id').first() - return TemplateResponse( - request, - 'problems/editorial.html', - { - 'problem': problem, - 'editorial': editorial, - 'can_admin_problem': can_admin_problem(request, problem), - } - ) - - @problem_site_tab( _("Replace problem statement"), key='replace_problem_statement', From b5dd303104c690b8ceb2c12bbbb5eb23a848764c Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:15:03 +0200 Subject: [PATCH 05/29] Partially-correct abstraction of problem_site_statement -> problem_site_document. --- oioioi/problems/problem_site.py | 40 ++++++++++++++------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index b9ff477c2..7254fd150 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -42,6 +42,7 @@ can_admin_problem, generate_add_to_contest_metadata, generate_model_solutions_context, + query_editorial, query_statement, query_zip, ) @@ -88,23 +89,14 @@ def problem_site_statement_zip_view(request, site_key, path): return query_zip(statement, path) -def check_for_statement(request, problem): - """Function checking if given problem has a ProblemStatement.""" - return bool(ProblemStatement.objects.filter(problem=problem)) - - -@problem_site_tab( - _("Problem statement"), key='statement', order=100, condition=check_for_statement -) -def problem_site_statement(request, problem): - statement = query_statement(problem.id) - if not statement: +def problem_site_document(request, problem, document): + if not document: statement_html = render_to_string( 'problems/no-problem-statement.html', {'problem': problem, 'can_admin_problem': can_admin_problem(request, problem)} ) - elif statement.extension == '.zip': + elif document.extension == '.zip': response = problem_site_statement_zip_view( request, problem.problemsite.url_key, 'index.html' ) @@ -128,25 +120,27 @@ def problem_site_statement(request, problem): return statement_html +def check_for_statement(request, problem): + """Function checking if given problem has a ProblemStatement.""" + return bool(ProblemStatement.objects.filter(problem=problem)) + +@problem_site_tab( + _("Problem statement"), key='statement', order=100, condition=check_for_statement +) +def problem_site_statement(request, problem): + statement = query_statement(problem.id) + return problem_site_document(request, problem, statement) + def show_editorial(request, problem): - """Show Editorial tab only if there's ≥1 ProblemEditorial.""" return ProblemEditorial.objects.filter(problem=problem).exists() and not request.contest @problem_site_tab( _("Editorial"), key='editorial', order=750, condition=show_editorial ) def problem_site_editorial(request, problem): - editorial = ProblemEditorial.objects.filter(problem=problem).order_by('language', 'id').first() - return TemplateResponse( - request, - 'problems/editorial.html', - { - 'problem': problem, - 'editorial': editorial, - 'can_admin_problem': can_admin_problem(request, problem), - } - ) + statement = query_editorial(problem.id) + return problem_site_document(request, problem, statement) def check_for_downloads(request, problem): From 5e143a2a76ebe1548a8a3e32beb916b3bd820b5d Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:21:13 +0200 Subject: [PATCH 06/29] Better check_for_statement implementation. --- oioioi/problems/problem_site.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 7254fd150..8b4a53b88 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -121,8 +121,7 @@ def problem_site_document(request, problem, document): return statement_html def check_for_statement(request, problem): - """Function checking if given problem has a ProblemStatement.""" - return bool(ProblemStatement.objects.filter(problem=problem)) + return ProblemStatement.objects.filter(problem=problem).exists() @problem_site_tab( _("Problem statement"), key='statement', order=100, condition=check_for_statement From b46875b72c8e6be6a38f01cda36a2e0fe5accc21 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:32:17 +0200 Subject: [PATCH 07/29] Add no-problem-editorial.html template. --- .../templates/problems/no-problem-editorial.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 oioioi/problems/templates/problems/no-problem-editorial.html diff --git a/oioioi/problems/templates/problems/no-problem-editorial.html b/oioioi/problems/templates/problems/no-problem-editorial.html new file mode 100644 index 000000000..dca8ec537 --- /dev/null +++ b/oioioi/problems/templates/problems/no-problem-editorial.html @@ -0,0 +1,15 @@ +{% load i18n %} + +
+ {% blocktrans %} +

This problem doesn't have a publicly available editorial.

+ {% endblocktrans %} +
+ +{% if can_admin_problem %} +
+ {% blocktrans %}

Problem's author:

{% endblocktrans %} +

{{ problem.author.first_name }} {{problem.author.last_name}} ({{problem.author.username}})

+

Send e-mail to the author

+
+{% endif %} From b43e247ca5d676808c061f4710a2e9031ca5508a Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:35:44 +0200 Subject: [PATCH 08/29] Load different page depending on document type. --- oioioi/problems/problem_site.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 8b4a53b88..a1cc78597 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -89,18 +89,27 @@ def problem_site_statement_zip_view(request, site_key, path): return query_zip(statement, path) -def problem_site_document(request, problem, document): +def problem_site_document(request, problem, document, type): if not document: - statement_html = render_to_string( - 'problems/no-problem-statement.html', - {'problem': problem, - 'can_admin_problem': can_admin_problem(request, problem)} - ) + if type == 'statement': + document_html = render_to_string( + 'problems/no-problem-statement.html', + {'problem': problem, + 'can_admin_problem': can_admin_problem(request, problem)} + ) + elif type == 'editorial': + document_html = render_to_string( + 'problems/no-problem-editorial.html', + {'problem': problem, + 'can_admin_problem': can_admin_problem(request, problem)} + ) + else: + raise Http404("Document not found") elif document.extension == '.zip': response = problem_site_statement_zip_view( request, problem.problemsite.url_key, 'index.html' ) - statement_html = render_to_string( + document_html = render_to_string( 'problems/from-zip-statement.html', {'problem': problem, 'statement': mark_safe(response.content.decode(errors="replace")), @@ -111,14 +120,14 @@ def problem_site_document(request, problem, document): 'problem_site_external_statement', kwargs={'site_key': problem.problemsite.url_key}, ) - statement_html = render_to_string( + document_html = render_to_string( 'problems/external-statement.html', {'problem': problem, 'statement_url': statement_url, 'can_admin_problem': can_admin_problem(request, problem)}, ) - return statement_html + return document_html def check_for_statement(request, problem): return ProblemStatement.objects.filter(problem=problem).exists() @@ -128,7 +137,7 @@ def check_for_statement(request, problem): ) def problem_site_statement(request, problem): statement = query_statement(problem.id) - return problem_site_document(request, problem, statement) + return problem_site_document(request, problem, statement, type='statement') def show_editorial(request, problem): @@ -139,7 +148,7 @@ def show_editorial(request, problem): ) def problem_site_editorial(request, problem): statement = query_editorial(problem.id) - return problem_site_document(request, problem, statement) + return problem_site_document(request, problem, statement, type='editorial') def check_for_downloads(request, problem): From e5a0afe19001c8b42ebd3b2e191b7ea196e83c0e Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:58:36 +0200 Subject: [PATCH 09/29] Generalise problem_site_statement_zip_view into problem_site_document_zip_view. --- oioioi/problems/problem_site.py | 16 +++++++++++----- oioioi/problems/urls.py | 7 +++++++ oioioi/problems/views.py | 4 ++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index a1cc78597..3eb44968b 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -81,12 +81,18 @@ def decorator(func): return decorator -def problem_site_statement_zip_view(request, site_key, path): +def problem_site_document_zip_view(request, site_key, path, type='statement'): problem = get_object_or_404(Problem, problemsite__url_key=site_key) - statement = query_statement(problem.id) - if not statement: + + document = None + if type == 'editorial': + document = query_editorial(problem.id) + else: + document = query_statement(problem.id) + + if not document: raise Http404 - return query_zip(statement, path) + return query_zip(document, path) def problem_site_document(request, problem, document, type): @@ -106,7 +112,7 @@ def problem_site_document(request, problem, document, type): else: raise Http404("Document not found") elif document.extension == '.zip': - response = problem_site_statement_zip_view( + response = problem_site_document_zip_view( request, problem.problemsite.url_key, 'index.html' ) document_html = render_to_string( diff --git a/oioioi/problems/urls.py b/oioioi/problems/urls.py index d64d7579b..c420cc3af 100644 --- a/oioioi/problems/urls.py +++ b/oioioi/problems/urls.py @@ -7,9 +7,16 @@ problem_site_patterns = [ path('site/', views.problem_site_view, name='problem_site'), + path( + 'site/editorial/', + views.problem_site_document_zip_view, + {'type': 'editorial'}, + name='problem_site_editorial_zip', + ), path( 'site/', views.problem_site_statement_zip_view, + {'type': 'statement'}, name='problem_site_statement_zip', ), path( diff --git a/oioioi/problems/views.py b/oioioi/problems/views.py index e22e73012..6ed010326 100644 --- a/oioioi/problems/views.py +++ b/oioioi/problems/views.py @@ -72,12 +72,12 @@ UserStatistics, ) -# problem_site_statement_zip_view is used in one of the tabs +# problem_site_document_zip_view is used in some of the tabs # in problem_site.py. We placed the view in problem_site.py # instead of views.py to avoid circular imports. We still import # it here to use it in urls.py. from oioioi.problems.problem_site import ( - problem_site_statement_zip_view, + problem_site_document_zip_view, problem_site_tab_registry, ) from oioioi.problems.problem_sources import problem_sources From 9f0f5310b8ec60a7e416e622b0a5314eece0423a Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 18:59:49 +0200 Subject: [PATCH 10/29] statement -> document in query_zip. --- oioioi/problems/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oioioi/problems/utils.py b/oioioi/problems/utils.py index 088e944cb..baf167dea 100644 --- a/oioioi/problems/utils.py +++ b/oioioi/problems/utils.py @@ -163,12 +163,12 @@ def query_editorial(problem_id): return query_document(editorials) -def query_zip(statement, path): - if statement.extension != '.zip': +def query_zip(document, path): + if document.extension != '.zip': raise SuspiciousOperation # ZipFile will call seek(), so we need a real file here - zip = zipfile.ZipFile(statement.content.read_using_cache()) + zip = zipfile.ZipFile(document.content.read_using_cache()) try: info = zip.getinfo(path) except KeyError: From 24932ea9b469f6ddd6f160ce6327c3572d2ef91c Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:02:57 +0200 Subject: [PATCH 11/29] Rename from-zip-statemnt.html template to from-zip-document.html. --- oioioi/problems/problem_site.py | 2 +- .../{from-zip-statement.html => from-zip-document.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename oioioi/problems/templates/problems/{from-zip-statement.html => from-zip-document.html} (100%) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 3eb44968b..8886a4ed6 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -116,7 +116,7 @@ def problem_site_document(request, problem, document, type): request, problem.problemsite.url_key, 'index.html' ) document_html = render_to_string( - 'problems/from-zip-statement.html', + 'problems/from-zip-document.html', {'problem': problem, 'statement': mark_safe(response.content.decode(errors="replace")), 'can_admin_problem': can_admin_problem(request, problem)} diff --git a/oioioi/problems/templates/problems/from-zip-statement.html b/oioioi/problems/templates/problems/from-zip-document.html similarity index 100% rename from oioioi/problems/templates/problems/from-zip-statement.html rename to oioioi/problems/templates/problems/from-zip-document.html From 94ed2a07ba8cf246e1a324328d122ff27ce634f5 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:04:05 +0200 Subject: [PATCH 12/29] Pass type argument to problem_site_document_zip_view in problem_site_document function. --- oioioi/problems/problem_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 8886a4ed6..d10a7fa51 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -113,7 +113,7 @@ def problem_site_document(request, problem, document, type): raise Http404("Document not found") elif document.extension == '.zip': response = problem_site_document_zip_view( - request, problem.problemsite.url_key, 'index.html' + request, problem.problemsite.url_key, 'index.html', type ) document_html = render_to_string( 'problems/from-zip-document.html', From bedd34ce54ac5594fc7b751de8aff813e842e6f0 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:13:26 +0200 Subject: [PATCH 13/29] Generalise problem_site_external_statement_view -> problem_site_external_statement_view . --- oioioi/problems/urls.py | 9 ++++++++- oioioi/problems/views.py | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/oioioi/problems/urls.py b/oioioi/problems/urls.py index c420cc3af..192a6cc7e 100644 --- a/oioioi/problems/urls.py +++ b/oioioi/problems/urls.py @@ -19,9 +19,16 @@ {'type': 'statement'}, name='problem_site_statement_zip', ), + path( + 'editorial/', + views.problem_site_external_document_view, + {'type': 'editorial'}, + name='problem_site_external_editorial', + ), path( 'statement/', - views.problem_site_external_statement_view, + views.problem_site_external_document_view, + {'type': 'statement'}, name='problem_site_external_statement', ), path( diff --git a/oioioi/problems/views.py b/oioioi/problems/views.py index 6ed010326..cfa402b0d 100644 --- a/oioioi/problems/views.py +++ b/oioioi/problems/views.py @@ -90,6 +90,7 @@ generate_add_to_contest_metadata, generate_model_solutions_context, get_prefetched_value, + query_editorial, query_statement, show_proposal_form, ) @@ -615,14 +616,20 @@ def build_link(tab): ) -def problem_site_external_statement_view(request, site_key): +def problem_site_external_document_view(request, site_key, type='statement'): problem = get_object_or_404(Problem, problemsite__url_key=site_key) - statement = query_statement(problem.id) - if not statement: + + document = None + if type == 'editorial': + document = query_editorial(problem.id) + elif type == 'statement': + document = query_statement(problem.id) + + if not document: raise Http404 - if statement.extension == '.zip' and not can_admin_problem(request, problem): + if document.extension == '.zip' and not can_admin_problem(request, problem): raise PermissionDenied - return stream_file(statement.content, statement.download_name) + return stream_file(document.content, document.download_name) def problem_site_external_attachment_view(request, site_key, attachment_id): From 520f6879f98b9ac30588f8300e575ec7c9ef9835 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:14:31 +0200 Subject: [PATCH 14/29] Make problem_site_document_zip_view throw Http404 for unknown document types. --- oioioi/problems/problem_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index d10a7fa51..389bfa96b 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -87,7 +87,7 @@ def problem_site_document_zip_view(request, site_key, path, type='statement'): document = None if type == 'editorial': document = query_editorial(problem.id) - else: + elif type == 'statement': document = query_statement(problem.id) if not document: From 010e8fe683683e2631a50d7eb2429dd96dadc03e Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:16:40 +0200 Subject: [PATCH 15/29] Correct document_url setting for external-statement.html page. --- oioioi/problems/problem_site.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 389bfa96b..6c34d987d 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -122,14 +122,24 @@ def problem_site_document(request, problem, document, type): 'can_admin_problem': can_admin_problem(request, problem)} ) else: - statement_url = reverse( - 'problem_site_external_statement', - kwargs={'site_key': problem.problemsite.url_key}, - ) + document_url = None + if type == 'editorial': + document_url = reverse( + 'problem_site_external_editorial', + kwargs={'site_key': problem.problemsite.url_key}, + ) + elif type == 'statement': + document_url = reverse( + 'problem_site_external_statement', + kwargs={'site_key': problem.problemsite.url_key}, + ) + else: + raise Http404("Document not found") + document_html = render_to_string( 'problems/external-statement.html', {'problem': problem, - 'statement_url': statement_url, + 'statement_url': document_url, 'can_admin_problem': can_admin_problem(request, problem)}, ) From 840d0dc2a6588120c3651c69f31340014b2b6315 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:17:58 +0200 Subject: [PATCH 16/29] Rename external-statement.html -> external-document.html. --- oioioi/problems/problem_site.py | 2 +- .../{external-statement.html => external-document.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename oioioi/problems/templates/problems/{external-statement.html => external-document.html} (100%) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 6c34d987d..90add8850 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -137,7 +137,7 @@ def problem_site_document(request, problem, document, type): raise Http404("Document not found") document_html = render_to_string( - 'problems/external-statement.html', + 'problems/external-document.html', {'problem': problem, 'statement_url': document_url, 'can_admin_problem': can_admin_problem(request, problem)}, diff --git a/oioioi/problems/templates/problems/external-statement.html b/oioioi/problems/templates/problems/external-document.html similarity index 100% rename from oioioi/problems/templates/problems/external-statement.html rename to oioioi/problems/templates/problems/external-document.html From 816fe54e903889567651d648c156aeeee6bb9101 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:23:23 +0200 Subject: [PATCH 17/29] Generalise external-document.html contents. --- oioioi/problems/problem_site.py | 3 ++- .../problems/templates/problems/external-document.html | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 90add8850..8a510b07c 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -139,7 +139,8 @@ def problem_site_document(request, problem, document, type): document_html = render_to_string( 'problems/external-document.html', {'problem': problem, - 'statement_url': document_url, + 'document_url': document_url, + 'document_type': type, 'can_admin_problem': can_admin_problem(request, problem)}, ) diff --git a/oioioi/problems/templates/problems/external-document.html b/oioioi/problems/templates/problems/external-document.html index d4a92954f..1d2b9c6d2 100644 --- a/oioioi/problems/templates/problems/external-document.html +++ b/oioioi/problems/templates/problems/external-document.html @@ -1,10 +1,16 @@ {% load i18n %}
- +
- {% blocktrans %}You can also open the problem's statement by clicking here.{% endblocktrans %} + {% if document_type == 'statement' %} + {% blocktrans %}You can also open the problem's statement by clicking here.{% endblocktrans %} + {% elif document_type == 'editorial' %} + {% blocktrans %}You can also open the problem's editorial by clicking here.{% endblocktrans %} + {% else %} + {% blocktrans %}You can also open this document by clicking here.{% endblocktrans %} + {% endif %}
{% if can_admin_problem %} From 554d851c7189e0340db1b0e11857fbb2a8df8be2 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:27:56 +0200 Subject: [PATCH 18/29] Wording change. --- oioioi/problems/templates/problems/no-problem-editorial.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oioioi/problems/templates/problems/no-problem-editorial.html b/oioioi/problems/templates/problems/no-problem-editorial.html index dca8ec537..bac1e586b 100644 --- a/oioioi/problems/templates/problems/no-problem-editorial.html +++ b/oioioi/problems/templates/problems/no-problem-editorial.html @@ -2,7 +2,7 @@
{% blocktrans %} -

This problem doesn't have a publicly available editorial.

+

This problem doesn't have any editorial available .

{% endblocktrans %}
From a62366429312fadd452d6a0a3040a43e1f403662 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:31:26 +0200 Subject: [PATCH 19/29] Consistent case ordering in problem_site_document. --- oioioi/problems/problem_site.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 8a510b07c..1e77b2299 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -123,14 +123,14 @@ def problem_site_document(request, problem, document, type): ) else: document_url = None - if type == 'editorial': + if type == 'statement': document_url = reverse( - 'problem_site_external_editorial', + 'problem_site_external_statement', kwargs={'site_key': problem.problemsite.url_key}, ) - elif type == 'statement': + elif type == 'editorial': document_url = reverse( - 'problem_site_external_statement', + 'problem_site_external_editorial', kwargs={'site_key': problem.problemsite.url_key}, ) else: From 6fda6e820e2ccbf7a84904f249389507d268fe93 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:32:54 +0200 Subject: [PATCH 20/29] Problem statement views before editorial views. --- oioioi/problems/urls.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/oioioi/problems/urls.py b/oioioi/problems/urls.py index 192a6cc7e..e0b63bac5 100644 --- a/oioioi/problems/urls.py +++ b/oioioi/problems/urls.py @@ -7,12 +7,6 @@ problem_site_patterns = [ path('site/', views.problem_site_view, name='problem_site'), - path( - 'site/editorial/', - views.problem_site_document_zip_view, - {'type': 'editorial'}, - name='problem_site_editorial_zip', - ), path( 'site/', views.problem_site_statement_zip_view, @@ -20,10 +14,10 @@ name='problem_site_statement_zip', ), path( - 'editorial/', - views.problem_site_external_document_view, + 'site/editorial/', + views.problem_site_document_zip_view, {'type': 'editorial'}, - name='problem_site_external_editorial', + name='problem_site_editorial_zip', ), path( 'statement/', @@ -31,6 +25,12 @@ {'type': 'statement'}, name='problem_site_external_statement', ), + path( + 'editorial/', + views.problem_site_external_document_view, + {'type': 'editorial'}, + name='problem_site_external_editorial', + ), path( 'attachment//', views.problem_site_external_attachment_view, From 1309e1d5d7747106b504a276b4020c0628688b54 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 28 May 2025 19:33:36 +0200 Subject: [PATCH 21/29] Fix view for pattern problem_site_statement_zip. --- oioioi/problems/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oioioi/problems/urls.py b/oioioi/problems/urls.py index e0b63bac5..d560aea52 100644 --- a/oioioi/problems/urls.py +++ b/oioioi/problems/urls.py @@ -9,7 +9,7 @@ path('site/', views.problem_site_view, name='problem_site'), path( 'site/', - views.problem_site_statement_zip_view, + views.problem_site_document_zip_view, {'type': 'statement'}, name='problem_site_statement_zip', ), From a2afaf4075194cc6f26c35ee23bb438a305b43e4 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Thu, 5 Jun 2025 11:26:25 +0200 Subject: [PATCH 22/29] Rename replace_problem_statement tab to replace_statement_or_editorial. --- oioioi/contests/admin.py | 2 +- oioioi/problems/problem_site.py | 6 +++--- oioioi/problems/tests/test_problem.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/oioioi/contests/admin.py b/oioioi/contests/admin.py index c6060d08d..00aa9b7e2 100644 --- a/oioioi/contests/admin.py +++ b/oioioi/contests/admin.py @@ -468,7 +468,7 @@ def _replace_statement_href(self, instance): return ( reverse('problem_site', args=(instance.problem.problemsite.url_key,)) + '?' - + urllib.parse.urlencode({'key': 'replace_problem_statement'}) + + urllib.parse.urlencode({'key': 'replace_statement_or_editorial'}) ) def _package_manage_href(self, instance): diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index 1e77b2299..d1b835da8 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -349,8 +349,8 @@ def problem_site_add_to_contest(request, problem): @problem_site_tab( - _("Replace problem statement"), - key='replace_problem_statement', + _("Replace statement or editorial"), + key='replace_statement_or_editorial', order=800, condition=can_admin_problem, ) @@ -371,7 +371,7 @@ def problem_site_replace_statement(request, problem): url = reverse( 'problem_site', kwargs={'site_key': problem.problemsite.url_key} ) - return redirect(url + '?key=replace_problem_statement') + return redirect(url + '?key=replace_statement_or_editorial') else: form.add_error(None, _("Picked statement file does not exist.")) else: diff --git a/oioioi/problems/tests/test_problem.py b/oioioi/problems/tests/test_problem.py index c799d805d..892203395 100644 --- a/oioioi/problems/tests/test_problem.py +++ b/oioioi/problems/tests/test_problem.py @@ -476,7 +476,7 @@ def test_tags_tab_user_with_permission(self): def test_statement_replacement(self): url = ( reverse('problem_site', kwargs={'site_key': '123'}) - + '?key=replace_problem_statement' + + '?key=replace_statement_or_editorial' ) self.assertTrue(self.client.login(username='test_user')) From 870d8785781eb6b3ff3a2105e40d40485bc2d85b Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 14:51:51 +0200 Subject: [PATCH 23/29] Update problem_site_replace_statement -> problem_site_replace_statement_or_editorial. --- oioioi/problems/problem_site.py | 53 ++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index d1b835da8..b287f79f7 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -354,32 +354,45 @@ def problem_site_add_to_contest(request, problem): order=800, condition=can_admin_problem, ) -def problem_site_replace_statement(request, problem): - statements = ProblemStatement.objects.filter(problem=problem) - filenames = [statement.filename for statement in statements] +def problem_site_replace_statement_or_editorial(request, problem): + statements = ProblemStatement .objects.filter(problem=problem) + editorials = ProblemEditorial.objects.filter(problem=problem) + + stmt_names = [s.filename for s in statements] + ed_names = [e.filename for e in editorials] + + stmt_form = ProblemStatementReplaceForm(stmt_names) + ed_form = ProblemStatementReplaceForm(ed_names) if request.method == 'POST': - form = PackageFileReuploadForm(filenames, request.POST, request.FILES) - if form.is_valid(): - statement_filename = form.cleaned_data['file_name'] - statements = [s for s in statements if s.filename == statement_filename] - if statements: - statement = statements[0] - new_statement_file = form.cleaned_data['file_replacement'] - statement.content = new_statement_file - statement.save() - url = reverse( - 'problem_site', kwargs={'site_key': problem.problemsite.url_key} - ) + form_type = request.POST.get('form_type') + if form_type == 'statement': + stmt_form = ProblemStatementReplaceForm(stmt_names, request.POST, request.FILES) + if stmt_form.is_valid(): + fn = stmt_form.cleaned_data['file_name'] + stmt = next(s for s in statements if s.filename == fn) + stmt.content = stmt_form.cleaned_data['file_replacement'] + stmt.save() + url = reverse('problem_site', kwargs={'site_key': problem.problemsite.url_key}) return redirect(url + '?key=replace_statement_or_editorial') - else: - form.add_error(None, _("Picked statement file does not exist.")) - else: - form = ProblemStatementReplaceForm(filenames) + elif form_type == 'editorial': + ed_form = ProblemStatementReplaceForm(ed_names, request.POST, request.FILES) + if ed_form.is_valid(): + fn = ed_form.cleaned_data['file_name'] + ed = next(e for e in editorials if e.filename == fn) + ed.content = ed_form.cleaned_data['file_replacement'] + ed.save() + url = reverse('problem_site', kwargs={'site_key': problem.problemsite.url_key}) + return redirect(url + '?key=replace_statement_or_editorial') + return TemplateResponse( request, 'problems/replace-problem-statement.html', - {'form': form, 'problem': problem}, + { + 'problem': problem, + 'statement_form': stmt_form, + 'editorial_form': ed_form, + }, ) From ccc5ef6a2eb2cbc11246ce9988b6ef13c87ee4c0 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 14:57:41 +0200 Subject: [PATCH 24/29] replace-problem-statement.html with two identical forms, one for statement, other for editorial. --- .../problems/replace-problem-statement.html | 92 ++++++++++++------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/oioioi/problems/templates/problems/replace-problem-statement.html b/oioioi/problems/templates/problems/replace-problem-statement.html index bf1a99356..1f7db33ca 100644 --- a/oioioi/problems/templates/problems/replace-problem-statement.html +++ b/oioioi/problems/templates/problems/replace-problem-statement.html @@ -10,54 +10,80 @@ {% trans "Manage package files" %}.

+ +

{% trans "Replace statement" %}

+ {% csrf_token %} + + + {% if statement_form.non_field_errors %} +
+ {% for err in statement_form.non_field_errors %} +
{{ err }}
+ {% endfor %} +
+ {% endif %} + +
+ + {{ statement_form.file_name|add_class:"form-control" }} + {% for err in statement_form.file_name.errors %} +
{{ err }}
+ {% endfor %} +
+
+ + {{ statement_form.file_replacement|add_class:"form-control" }} + {% for err in statement_form.file_replacement.errors %} +
{{ err }}
+ {% endfor %} +
+ +
+ +
+
+ +

{% trans "Replace editorial" %}

+
{% csrf_token %} - {% if form.non_field_errors %} + + + {% if editorial_form.non_field_errors %}
- {% for error in form.non_field_errors %} - + {% for err in editorial_form.non_field_errors %} +
{{ err }}
{% endfor %}
{% endif %} -
- {% if display_labels != False %} - - {% endif %} - {{ form.file_name | add_class:"form-control" }} - {% for error in form.file_name.errors %} -
{{ error }}
+
+ + {{ editorial_form.file_name|add_class:"form-control" }} + {% for err in editorial_form.file_name.errors %} +
{{ err }}
{% endfor %} - {% if form.file_name.help_text %} -
{{ form.file_name.help_text }}
- {% endif %}
-
- {% if display_labels != False %} - - {% endif %} - {{ form.file_replacement | add_class:"form-control" }} - {% for error in form.file_replacement.errors %} -
{{ error }}
+
+ + {{ editorial_form.file_replacement|add_class:"form-control" }} + {% for err in editorial_form.file_replacement.errors %} +
{{ err }}
{% endfor %} - {% if form.file_replacement.help_text %} -
{{ form.file_replacement.help_text }}
- {% endif %}
- {% block upload_btn %} - - {% endblock %} +
From b19cf67c3bd06e7739cf24b746b268c26f151e5e Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 14:59:05 +0200 Subject: [PATCH 25/29] Restore replace-problem-statement.html to previous form. --- .../problems/replace-problem-statement.html | 92 +++++++------------ 1 file changed, 33 insertions(+), 59 deletions(-) diff --git a/oioioi/problems/templates/problems/replace-problem-statement.html b/oioioi/problems/templates/problems/replace-problem-statement.html index 1f7db33ca..bf1a99356 100644 --- a/oioioi/problems/templates/problems/replace-problem-statement.html +++ b/oioioi/problems/templates/problems/replace-problem-statement.html @@ -10,80 +10,54 @@ {% trans "Manage package files" %}.

- -

{% trans "Replace statement" %}

- {% csrf_token %} - - - {% if statement_form.non_field_errors %} -
- {% for err in statement_form.non_field_errors %} -
{{ err }}
- {% endfor %} -
- {% endif %} - -
- - {{ statement_form.file_name|add_class:"form-control" }} - {% for err in statement_form.file_name.errors %} -
{{ err }}
- {% endfor %} -
-
- - {{ statement_form.file_replacement|add_class:"form-control" }} - {% for err in statement_form.file_replacement.errors %} -
{{ err }}
- {% endfor %} -
- -
- -
-
- -

{% trans "Replace editorial" %}

-
{% csrf_token %} - - - {% if editorial_form.non_field_errors %} + {% if form.non_field_errors %}
- {% for err in editorial_form.non_field_errors %} -
{{ err }}
+ {% for error in form.non_field_errors %} + {% endfor %}
{% endif %} -
- - {{ editorial_form.file_name|add_class:"form-control" }} - {% for err in editorial_form.file_name.errors %} -
{{ err }}
+
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_name | add_class:"form-control" }} + {% for error in form.file_name.errors %} +
{{ error }}
{% endfor %} + {% if form.file_name.help_text %} +
{{ form.file_name.help_text }}
+ {% endif %}
-
- - {{ editorial_form.file_replacement|add_class:"form-control" }} - {% for err in editorial_form.file_replacement.errors %} -
{{ err }}
+
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_replacement | add_class:"form-control" }} + {% for error in form.file_replacement.errors %} +
{{ error }}
{% endfor %} + {% if form.file_replacement.help_text %} +
{{ form.file_replacement.help_text }}
+ {% endif %}
- + {% block upload_btn %} + + {% endblock %}
From 2b0892edb24711c2d72c0d28cd7f11d491a6562f Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 15:10:36 +0200 Subject: [PATCH 26/29] Initial implementation of two forms via includes. --- .../ingredients/document-replace-form.html | 51 +++++++++++++++ .../problems/replace-problem-statement.html | 62 ++++--------------- 2 files changed, 63 insertions(+), 50 deletions(-) create mode 100644 oioioi/problems/templates/problems/ingredients/document-replace-form.html diff --git a/oioioi/problems/templates/problems/ingredients/document-replace-form.html b/oioioi/problems/templates/problems/ingredients/document-replace-form.html new file mode 100644 index 000000000..53e81e58a --- /dev/null +++ b/oioioi/problems/templates/problems/ingredients/document-replace-form.html @@ -0,0 +1,51 @@ +

{{ title }}

+
+ + {% csrf_token %} + {% if form.non_field_errors %} +
+ {% for error in form.non_field_errors %} + + {% endfor %} +
+ {% endif %} + +
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_name | add_class:"form-control" }} + {% for error in form.file_name.errors %} +
{{ error }}
+ {% endfor %} + {% if form.file_name.help_text %} +
{{ form.file_name.help_text }}
+ {% endif %} +
+ +
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_replacement | add_class:"form-control" }} + {% for error in form.file_replacement.errors %} +
{{ error }}
+ {% endfor %} + {% if form.file_replacement.help_text %} +
{{ form.file_replacement.help_text }}
+ {% endif %} +
+ +
+ {% block upload_btn %} + + {% endblock %} +
+
diff --git a/oioioi/problems/templates/problems/replace-problem-statement.html b/oioioi/problems/templates/problems/replace-problem-statement.html index bf1a99356..3f2492788 100644 --- a/oioioi/problems/templates/problems/replace-problem-statement.html +++ b/oioioi/problems/templates/problems/replace-problem-statement.html @@ -10,55 +10,17 @@ {% trans "Manage package files" %}.

-
- - {% csrf_token %} - {% if form.non_field_errors %} -
- {% for error in form.non_field_errors %} - - {% endfor %} -
- {% endif %} - -
- {% if display_labels != False %} - - {% endif %} - {{ form.file_name | add_class:"form-control" }} - {% for error in form.file_name.errors %} -
{{ error }}
- {% endfor %} - {% if form.file_name.help_text %} -
{{ form.file_name.help_text }}
- {% endif %} -
- -
- {% if display_labels != False %} - - {% endif %} - {{ form.file_replacement | add_class:"form-control" }} - {% for error in form.file_replacement.errors %} -
{{ error }}
- {% endfor %} - {% if form.file_replacement.help_text %} -
{{ form.file_replacement.help_text }}
- {% endif %} -
- -
- {% block upload_btn %} - - {% endblock %} -
-
+{% include "problems/ingredients/document-replace-form.html" with + title=_("Replace statement") + form=statement_form + form_type="statement" + button_label=_("Submit statement") +%} +{% include "problems/ingredients/document-replace-form.html" with + title=_("Replace editorial") + form=editorial_form + form_type="editorial" + button_label=_("Submit editorial") +%} From eb3fa8edacfaa1ca6afa9933d95ad58a8baa4d95 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 23:11:31 +0200 Subject: [PATCH 27/29] Migration to create ProblemEditorial model. --- .../migrations/0039_problemeditorial.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 oioioi/problems/migrations/0039_problemeditorial.py diff --git a/oioioi/problems/migrations/0039_problemeditorial.py b/oioioi/problems/migrations/0039_problemeditorial.py new file mode 100644 index 000000000..56d2decd2 --- /dev/null +++ b/oioioi/problems/migrations/0039_problemeditorial.py @@ -0,0 +1,29 @@ +# Generated by Django 5.2.3 on 2025-06-10 20:59 + +import django.db.models.deletion +import oioioi.filetracker.fields +import oioioi.problems.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('problems', '0038_alter_algorithmtaglocalization_language_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='ProblemEditorial', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('language', models.CharField(blank=True, max_length=6, null=True, verbose_name='language code')), + ('content', oioioi.filetracker.fields.FileField(max_length=255, upload_to=oioioi.problems.models.make_problem_filename, verbose_name='content')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='editorials', to='problems.problem')), + ], + options={ + 'verbose_name': 'problem editorial', + 'verbose_name_plural': 'problem editorials', + }, + ), + ] From 33410d3b7420cf9b03fadc5b25f0cc5f2a7e8929 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Tue, 10 Jun 2025 23:12:04 +0200 Subject: [PATCH 28/29] Slightly better includes (still not working). --- .../templates/problems/replace-problem-statement.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/oioioi/problems/templates/problems/replace-problem-statement.html b/oioioi/problems/templates/problems/replace-problem-statement.html index 3f2492788..c8de6253f 100644 --- a/oioioi/problems/templates/problems/replace-problem-statement.html +++ b/oioioi/problems/templates/problems/replace-problem-statement.html @@ -12,15 +12,11 @@

{% include "problems/ingredients/document-replace-form.html" with - title=_("Replace statement") + title="{% trans "Replace statement" %}" form=statement_form - form_type="statement" - button_label=_("Submit statement") %} {% include "problems/ingredients/document-replace-form.html" with - title=_("Replace editorial") + title="{% trans "Replace editorial" %}" form=editorial_form - form_type="editorial" - button_label=_("Submit editorial") %} From 065130f4a5e3b5b3484380d55cf8fdf20b482972 Mon Sep 17 00:00:00 2001 From: Grzegorz Krawczyk Date: Wed, 11 Jun 2025 08:19:56 +0200 Subject: [PATCH 29/29] Restore original version of replace-problem-statement.html. --- oioioi/problems/problem_site.py | 2 +- .../problems/replace-problem-statement.html | 58 ++++++++++++++++--- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index b287f79f7..af5f93d41 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -390,7 +390,7 @@ def problem_site_replace_statement_or_editorial(request, problem): 'problems/replace-problem-statement.html', { 'problem': problem, - 'statement_form': stmt_form, + 'form': stmt_form, 'editorial_form': ed_form, }, ) diff --git a/oioioi/problems/templates/problems/replace-problem-statement.html b/oioioi/problems/templates/problems/replace-problem-statement.html index c8de6253f..bf1a99356 100644 --- a/oioioi/problems/templates/problems/replace-problem-statement.html +++ b/oioioi/problems/templates/problems/replace-problem-statement.html @@ -10,13 +10,55 @@ {% trans "Manage package files" %}.

+
+ + {% csrf_token %} + {% if form.non_field_errors %} +
+ {% for error in form.non_field_errors %} + + {% endfor %} +
+ {% endif %} + +
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_name | add_class:"form-control" }} + {% for error in form.file_name.errors %} +
{{ error }}
+ {% endfor %} + {% if form.file_name.help_text %} +
{{ form.file_name.help_text }}
+ {% endif %} +
+ +
+ {% if display_labels != False %} + + {% endif %} + {{ form.file_replacement | add_class:"form-control" }} + {% for error in form.file_replacement.errors %} +
{{ error }}
+ {% endfor %} + {% if form.file_replacement.help_text %} +
{{ form.file_replacement.help_text }}
+ {% endif %} +
+ +
+ {% block upload_btn %} + + {% endblock %} +
+
-{% include "problems/ingredients/document-replace-form.html" with - title="{% trans "Replace statement" %}" - form=statement_form -%} -{% include "problems/ingredients/document-replace-form.html" with - title="{% trans "Replace editorial" %}" - form=editorial_form -%}