forked from cms-dev/cms
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
247 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
# Copyright © 2010-2012 Matteo Boscariol <[email protected]> | ||
# Copyright © 2013 Bernard Blackham <[email protected]> | ||
# Copyright © 2013-2018 Luca Wehrstedt <[email protected]> | ||
# Copyright © 2014 Vytis Banaitis <[email protected]> | ||
# Copyright © 2016 Myungwoo Chun <[email protected]> | ||
# Copyright © 2016 Masaki Hara <[email protected]> | ||
# Copyright © 2016 Amir Keivan Mohtashami <[email protected]> | ||
|
@@ -53,7 +54,7 @@ | |
# fsobject | ||
"FSObject", "LargeObject", | ||
# contest | ||
"Contest", "Announcement", | ||
"Contest", "Announcement", "ContestAttachment", | ||
# user | ||
"User", "Team", "Participation", "Message", "Question", | ||
# admin | ||
|
@@ -96,7 +97,7 @@ | |
from .base import Base | ||
from .fsobject import FSObject, LargeObject | ||
from .admin import Admin | ||
from .contest import Contest, Announcement | ||
from .contest import Contest, Announcement, ContestAttachment | ||
from .user import User, Team, Participation, Message, Question | ||
from .task import Task, Statement, Attachment, Dataset, Manager, Testcase | ||
from .submission import Submission, File, Token, SubmissionResult, \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
# Copyright © 2010-2012 Matteo Boscariol <[email protected]> | ||
# Copyright © 2012-2018 Luca Wehrstedt <[email protected]> | ||
# Copyright © 2013 Bernard Blackham <[email protected]> | ||
# Copyright © 2014 Vytis Banaitis <[email protected]> | ||
# Copyright © 2016 Myungwoo Chun <[email protected]> | ||
# Copyright © 2016 Amir Keivan Mohtashami <[email protected]> | ||
# Copyright © 2018 William Di Luigi <[email protected]> | ||
|
@@ -32,12 +33,14 @@ | |
from sqlalchemy.dialects.postgresql import ARRAY | ||
from sqlalchemy.ext.orderinglist import ordering_list | ||
from sqlalchemy.orm import relationship | ||
from sqlalchemy.schema import Column, ForeignKey, CheckConstraint | ||
from sqlalchemy.orm.collections import attribute_mapped_collection | ||
from sqlalchemy.schema import Column, ForeignKey, CheckConstraint, \ | ||
UniqueConstraint | ||
from sqlalchemy.types import Integer, Unicode, DateTime, Interval, Enum, \ | ||
Boolean, String | ||
|
||
from cms import TOKEN_MODE_DISABLED, TOKEN_MODE_FINITE, TOKEN_MODE_INFINITE | ||
from . import Codename, Base, Admin | ||
from . import Codename, Filename, Digest, Base, Admin | ||
|
||
|
||
class Contest(Base): | ||
|
@@ -276,6 +279,13 @@ class Contest(Base): | |
passive_deletes=True, | ||
back_populates="contest") | ||
|
||
attachments = relationship( | ||
"ContestAttachment", | ||
collection_class=attribute_mapped_collection("filename"), | ||
cascade="all, delete-orphan", | ||
passive_deletes=True, | ||
back_populates="contest") | ||
|
||
participations = relationship( | ||
"Participation", | ||
cascade="all, delete-orphan", | ||
|
@@ -307,6 +317,40 @@ def phase(self, timestamp): | |
return 3 | ||
|
||
|
||
class ContestAttachment(Base): | ||
"""Class to store contest related files to give to the user. | ||
""" | ||
__tablename__ = 'contest_attachments' | ||
__table_args__ = ( | ||
UniqueConstraint('contest_id', 'filename'), | ||
) | ||
|
||
# Auto increment primary key. | ||
id = Column( | ||
Integer, | ||
primary_key=True) | ||
|
||
# Contest (id and object) owning the attachment. | ||
contest_id = Column( | ||
Integer, | ||
ForeignKey(Contest.id, | ||
onupdate="CASCADE", ondelete="CASCADE"), | ||
nullable=False, | ||
index=True) | ||
contest = relationship( | ||
Contest, | ||
back_populates="attachments") | ||
|
||
# Filename and digest of the provided attachment. | ||
filename = Column( | ||
Filename, | ||
nullable=False) | ||
digest = Column( | ||
Digest, | ||
nullable=False) | ||
|
||
|
||
class Announcement(Base): | ||
"""Class to store a messages sent by the contest managers to all | ||
the users. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
# Copyright © 2010-2012 Stefano Maggiolo <[email protected]> | ||
# Copyright © 2010-2012 Matteo Boscariol <[email protected]> | ||
# Copyright © 2013-2018 Luca Wehrstedt <[email protected]> | ||
# Copyright © 2014 Vytis Banaitis <[email protected]> | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
|
@@ -33,7 +34,7 @@ | |
from . import SessionGen, Digest, Contest, Participation, Statement, \ | ||
Attachment, Task, Manager, Dataset, Testcase, Submission, File, \ | ||
SubmissionResult, Executable, UserTest, UserTestFile, UserTestManager, \ | ||
UserTestResult, UserTestExecutable, PrintJob | ||
UserTestResult, UserTestExecutable, PrintJob, ContestAttachment | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
@@ -288,6 +289,8 @@ def enumerate_files( | |
contest_q = contest_q.filter(Contest.id == contest.id) | ||
|
||
queries = list() | ||
queries.append(contest_q.join(Contest.attachments) | ||
.with_entities(ContestAttachment.digest)) | ||
|
||
task_q = contest_q.join(Contest.tasks) | ||
queries.append(task_q.join(Task.statements).with_entities(Statement.digest)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
# Copyright © 2016 Myungwoo Chun <[email protected]> | ||
# Copyright © 2016 Peyman Jabbarzade Ganje <[email protected]> | ||
# Copyright © 2016 Amir Keivan Mohtashami <[email protected]> | ||
# Copyright © 2018 Vytis Banaitis <[email protected]> | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
|
@@ -30,6 +31,8 @@ | |
from .contest import \ | ||
AddContestHandler, \ | ||
ContestHandler, \ | ||
AddContestAttachmentHandler, \ | ||
ContestAttachmentHandler, \ | ||
OverviewHandler, \ | ||
ResourcesListHandler, \ | ||
ContestListHandler, \ | ||
|
@@ -120,6 +123,8 @@ | |
(r"/contests/([0-9]+)/remove", RemoveContestHandler), | ||
(r"/contests/add", AddContestHandler), | ||
(r"/contest/([0-9]+)", ContestHandler), | ||
(r"/contest/([0-9]+)/attachments/add", AddContestAttachmentHandler), | ||
(r"/contest/([0-9]+)/attachment/([0-9]+)", ContestAttachmentHandler), | ||
(r"/contest/([0-9]+)/overview", OverviewHandler), | ||
(r"/contest/([0-9]+)/resourceslist", ResourcesListHandler), | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
# Copyright © 2012-2015 Luca Wehrstedt <[email protected]> | ||
# Copyright © 2014 Artem Iglikov <[email protected]> | ||
# Copyright © 2014 Fabian Gundlach <[email protected]> | ||
# Copyright © 2014-2024 Vytis Banaitis <[email protected]> | ||
# Copyright © 2016 Myungwoo Chun <[email protected]> | ||
# Copyright © 2016 Amir Keivan Mohtashami <[email protected]> | ||
# Copyright © 2018 William Di Luigi <[email protected]> | ||
|
@@ -28,8 +29,14 @@ | |
""" | ||
|
||
try: | ||
import tornado4.web as tornado_web | ||
except ImportError: | ||
import tornado.web as tornado_web | ||
|
||
from cms import ServiceCoord, get_service_shards, get_service_address | ||
from cms.db import Contest, Participation, Submission | ||
from cms.db import Contest, Participation, Session, Submission, \ | ||
ContestAttachment | ||
from cmscommon.datetime import make_datetime | ||
|
||
from .base import BaseHandler, SimpleContestHandler, SimpleHandler, \ | ||
|
@@ -142,6 +149,76 @@ def post(self, contest_id): | |
self.redirect(self.url("contest", contest_id)) | ||
|
||
|
||
class AddContestAttachmentHandler(BaseHandler): | ||
"""Add an attachment to a contest. | ||
""" | ||
@require_permission(BaseHandler.PERMISSION_ALL) | ||
def get(self, contest_id): | ||
self.contest = self.safe_get_item(Contest, contest_id) | ||
|
||
self.r_params = self.render_params() | ||
self.render("add_contest_attachment.html", **self.r_params) | ||
|
||
@require_permission(BaseHandler.PERMISSION_ALL) | ||
def post(self, contest_id): | ||
fallback_page = self.url("contest", contest_id, "attachments", "add") | ||
|
||
self.contest = self.safe_get_item(Contest, contest_id) | ||
|
||
attachment = self.request.files["attachment"][0] | ||
contest_name = self.contest.name | ||
self.sql_session.close() | ||
|
||
try: | ||
digest = self.service.file_cacher.put_file_content( | ||
attachment["body"], | ||
"Contest attachment for %s" % contest_name) | ||
except Exception as error: | ||
self.service.add_notification( | ||
make_datetime(), | ||
"Attachment storage failed", | ||
repr(error)) | ||
self.redirect(fallback_page) | ||
return | ||
|
||
# TODO verify that there's no other Attachment with that filename | ||
# otherwise we'd trigger an IntegrityError for constraint violation | ||
|
||
self.sql_session = Session() | ||
self.contest = self.safe_get_item(Contest, contest_id) | ||
|
||
attachment = ContestAttachment(attachment["filename"], digest, contest=self.contest) | ||
self.sql_session.add(attachment) | ||
|
||
if self.try_commit(): | ||
self.redirect(self.url("contest", contest_id)) | ||
else: | ||
self.redirect(fallback_page) | ||
|
||
|
||
class ContestAttachmentHandler(BaseHandler): | ||
"""Delete an attachment. | ||
""" | ||
# No page for single attachments. | ||
|
||
@require_permission(BaseHandler.PERMISSION_ALL) | ||
def delete(self, contest_id, attachment_id): | ||
attachment = self.safe_get_item(ContestAttachment, attachment_id) | ||
self.contest = self.safe_get_item(Contest, contest_id) | ||
|
||
# Protect against URLs providing incompatible parameters. | ||
if attachment.contest is not self.contest: | ||
raise tornado_web.HTTPError(404) | ||
|
||
self.sql_session.delete(attachment) | ||
self.try_commit() | ||
|
||
# Page to redirect to. | ||
self.write("%s" % self.contest.id) | ||
|
||
|
||
class OverviewHandler(BaseHandler): | ||
"""Home page handler, with queue and workers statuses. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{% extends "base.html" %} | ||
|
||
{% block core %} | ||
<div class="core_title"> | ||
<h1><a href="{{ url("contest", contest.id) }}">{{ contest.description }} ({{ contest.name }})</a> - Upload attachment</h1> | ||
</div> | ||
<form enctype="multipart/form-data" action="{{ url("contest", contest.id, "attachments", "add") }}" method="POST"> | ||
{{ xsrf_form_html|safe }} | ||
<input type="file" name="attachment"/><br/> | ||
<input type="submit" value="Upload"> | ||
<input type="Reset" > | ||
</form> | ||
{% endblock core %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
# Copyright © 2013 Bernard Blackham <[email protected]> | ||
# Copyright © 2014 Artem Iglikov <[email protected]> | ||
# Copyright © 2014 Fabian Gundlach <[email protected]> | ||
# Copyright © 2014 Vytis Banaitis <[email protected]> | ||
# Copyright © 2015-2018 William Di Luigi <[email protected]> | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
|
@@ -31,6 +32,7 @@ | |
LogoutHandler, \ | ||
RegistrationHandler, \ | ||
StartHandler, \ | ||
ContestAttachmentViewHandler, \ | ||
NotificationsHandler, \ | ||
PrintingHandler, \ | ||
DocumentationHandler | ||
|
@@ -62,6 +64,7 @@ | |
(r"/logout", LogoutHandler), | ||
(r"/register", RegistrationHandler), | ||
(r"/start", StartHandler), | ||
(r"/attachments/(.*)", ContestAttachmentViewHandler), | ||
(r"/notifications", NotificationsHandler), | ||
(r"/printing", PrintingHandler), | ||
(r"/documentation", DocumentationHandler), | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
# Copyright © 2013 Bernard Blackham <[email protected]> | ||
# Copyright © 2014 Artem Iglikov <[email protected]> | ||
# Copyright © 2014 Fabian Gundlach <[email protected]> | ||
# Copyright © 2014 Vytis Banaitis <[email protected]> | ||
# Copyright © 2015-2018 William Di Luigi <[email protected]> | ||
# Copyright © 2021 Grace Hawkins <[email protected]> | ||
# | ||
|
@@ -49,7 +50,8 @@ | |
UnacceptablePrintJob | ||
from cmscommon.crypto import hash_password, validate_password | ||
from cmscommon.datetime import make_datetime, make_timestamp | ||
from .contest import ContestHandler | ||
from cmscommon.mimetypes import get_type_for_file_name | ||
from .contest import ContestHandler, FileHandler | ||
from ..phase_management import actual_phase_required | ||
|
||
|
||
|
@@ -271,6 +273,27 @@ def post(self): | |
self.redirect(self.contest_url()) | ||
|
||
|
||
class ContestAttachmentViewHandler(FileHandler): | ||
"""Shows an attachment file of a task in the contest. | ||
""" | ||
@tornado_web.authenticated | ||
@actual_phase_required(0, 3) | ||
@multi_contest | ||
def get(self, filename): | ||
if filename not in self.contest.attachments: | ||
raise tornado_web.HTTPError(404) | ||
|
||
attachment = self.contest.attachments[filename].digest | ||
self.sql_session.close() | ||
|
||
mimetype = get_type_for_file_name(filename) | ||
if mimetype is None: | ||
mimetype = 'application/octet-stream' | ||
|
||
self.fetch(attachment, mimetype, filename) | ||
|
||
|
||
class NotificationsHandler(ContestHandler): | ||
"""Displays notifications. | ||
|
Oops, something went wrong.