Skip to content

Commit

Permalink
Timed problem release (#210) (no new checks)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdabtieu committed Jan 3, 2025
1 parent 40cb5bd commit 081d15a
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 134 deletions.
15 changes: 5 additions & 10 deletions src/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,17 +221,12 @@ def dl_file(problem_id):
@app.route("/dl/<contest_id>/<problem_id>.zip")
@login_required
def dl_contest(contest_id, problem_id):
contest = db.execute("SELECT * FROM contests WHERE id=?", contest_id)
if len(contest) == 0:
from views.contest import _get_contest, _get_problem
_, err = _get_contest(contest_id)
if err:
return abort(404)
# Ensure contest started or user is admin
start = parse_datetime(contest[0]["start"])
if datetime.utcnow() < start and not check_perm(["ADMIN", "SUPERADMIN", "CONTENT_MANAGER"]):
return abort(404)
problem = db.execute(("SELECT * FROM contest_problems WHERE contest_id=? "
"AND problem_id=?"), contest_id, problem_id)
if len(problem) == 0 or (problem[0]["status"] == PROBLEM_STAT["DRAFT"] and
not check_perm(["ADMIN", "SUPERADMIN"])):
_, err = _get_problem(contest_id, problem_id)
if err:
return abort(404)
return send_from_directory("dl/", f"{contest_id}/{problem_id}.zip",
as_attachment=True)
Expand Down
7 changes: 5 additions & 2 deletions src/migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,18 @@
'point_value' integer NOT NULL DEFAULT(0),
'category' varchar(64),
'flag' varchar(256) NOT NULL,
'status' integer NOT NULL DEFAULT(0),
'publish_timestamp' datetime DEFAULT(datetime('now')),
'score_min' integer NOT NULL DEFAULT(0),
'score_max' integer NOT NULL DEFAULT(0),
'score_users' integer NOT NULL DEFAULT(-1),
'flag_hint' varchar(256) NOT NULL DEFAULT(''),
'instanced' boolean NOT NULL DEFAULT(0),
UNIQUE(contest_id, problem_id) ON CONFLICT ABORT
)""")
);
""")
db.execute("INSERT INTO contest_problems_migration SELECT contest_id, problem_id, name, point_value, category, flag, draft, score_min, score_max, score_users, flag_hint, instanced FROM contest_problems")
db.execute("UPDATE contest_problems_migration SET publish_timestamp = datetime('now') WHERE publish_timestamp = 0")
db.execute("UPDATE contest_problems_migration SET publish_timestamp = NULL WHERE publish_timestamp = 1")
db.execute("DROP TABLE contest_problems")
db.execute("ALTER TABLE contest_problems_migration RENAME TO contest_problems")

Expand Down
2 changes: 1 addition & 1 deletion src/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ CREATE TABLE 'contest_problems' (
'point_value' integer NOT NULL DEFAULT(0),
'category' varchar(64),
'flag' varchar(256) NOT NULL,
'status' integer NOT NULL DEFAULT(0), -- 0: published, 1: draft
'publish_timestamp' datetime DEFAULT(datetime('now')),
'score_min' integer NOT NULL DEFAULT(0),
'score_max' integer NOT NULL DEFAULT(0),
'score_users' integer NOT NULL DEFAULT(-1),
Expand Down
30 changes: 26 additions & 4 deletions src/templates/contest/problem/create.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,22 @@ <h1>Create Problem</h1>
<input type="checkbox" name="instanced">
</div>
<input class="form-control mb-3" type="file" id="file" name="file" accept=".zip">
<div class="form-control mb-3" style="border: 0;">
<input type="checkbox" id="draft" name="draft">
<label for="draft">Draft?</label>
<div class="mb-3 toggle-input">
<div style="width: 300px;">
<span>Publish Now</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="draft">
</div>
<span>Publish Later</span>
</div>
<div class="form-floating" style="width: 100%;">
<input class="form-control"
type="datetime-local"
id="publish_timestamp"
name="publish_timestamp"
placeholder="Publish Time (optional)">
<label for="publish_timestamp">Publish Time (optional)</label>
</div>
</div>
<input class="btn btn-primary" type="submit" id="submit" name="submit" value="Create">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
Expand Down Expand Up @@ -177,5 +190,14 @@ <h1>Create Problem</h1>
.querySelectorAll("input")
.forEach(e => e.setAttribute("required", ""));
}

document.querySelector("form").onsubmit = function(event) {
var formPub = this.querySelector("#publish_timestamp");
if (formPub.value !== "") {
var pub = new Date(formPub.value).toISOString();
formPub.setAttribute("type", "text");
formPub.value = pub;
}
}
</script>
{% endblock %}
{% endblock %}
51 changes: 50 additions & 1 deletion src/templates/contest/problem/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{% block active %}Contests{% endblock %}

{% block preload %}
<link rel="preload" href="/api/contest/problem/description?cid={{ request.path.split('/')[2] }}&pid={{ request.path.split('/')[4] }}" as="fetch" crossorigin="anonymous">
<link rel="preload" href="/api/contest/problem?cid={{ request.path.split('/')[2] }}&pid={{ request.path.split('/')[4] }}" as="fetch" crossorigin="anonymous">
{% endblock %}

{% block main %}
Expand Down Expand Up @@ -84,6 +84,33 @@ <h1>Edit {{ data["name"] }}</h1>
<label class="input-group-text" for="file">New File (optional)</label>
<input class="form-control" type="file" id="file" name="file" accept=".zip">
</div>
<div class="mb-3 toggle-input">
<div style="width: 300px;">
<span>Publish Now</span>
<div class="form-check form-switch">
<input class="form-check-input"
type="checkbox"
name="draft"
{{ 'checked' if data['publish_later'] else 'disabled' }}>
</div>
<span>Publish Later</span>
</div>
<div class="form-floating" style="width: 100%;">
<input
{% if data['publish_timestamp'] %}
class="form-control dtl"
{% else %}
class="form-control"
{% endif %}
type="datetime-local"
id="publish_timestamp"
name="publish_timestamp"
placeholder="Publish Time (optional)"
{% if data['publish_timestamp'] %} value="{{ data['publish_timestamp'] }}" {% endif %}
{% if not data['publish_later'] %} disabled {% endif %}>
<label for="publish_timestamp">Publish Time (optional)</label>
</div>
</div>
<input class="btn btn-primary" type="submit" id="submit" name="submit" value="Submit">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
</form>
Expand Down Expand Up @@ -141,5 +168,27 @@ <h1>Edit {{ data["name"] }}</h1>
hints.value = b["data"]["hints"];
updateHints();
});

document.querySelectorAll(".dtl").forEach(function (e) {
var split = e.getAttribute("value").split(" ");
var dateSplit = split[0].split("-");
var final = dateSplit[1] + "/" + dateSplit[2] + "/" + dateSplit[0] + " " + split[1];
var parsed = new Date(final + " UTC").toString().split(" ");
e.value = `${ parsed[3] }-${ getMonthFromString(parsed[1]) }-${ parsed[2] }T${ parsed[4] }`;

function getMonthFromString(mon) {
var str = (new Date(Date.parse(mon + " 1, 2012")).getMonth() + 1).toString();
return str.length == 2 ? str : "0" + str;
}
});

document.querySelector("form").onsubmit = function(event) {
var formPub = this.querySelector("#publish_timestamp");
if (formPub.value !== "") {
var pub = new Date(formPub.value).toISOString();
formPub.setAttribute("type", "text");
formPub.value = pub;
}
}
</script>
{% endblock %}
4 changes: 2 additions & 2 deletions src/templates/contest/problem/problem.html
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ <h3 class="card-title">Live Instance</h3>
</a>
<br><a href="{{ request.path }}/edit">Edit problem</a>
<br><a href="{{ request.path }}/download">Download problem</a>
{% if data["status"] == 1 %}
{% if data["show_publish_btn"] %}
<br><a href="#" id="btn-publish" onclick="">
Publish problem
</a>
Expand Down Expand Up @@ -201,7 +201,7 @@ <h3 class="card-title">Live Instance</h3>
document.getElementById("hint").classList.toggle("hidden");
});
</script>
{% if data["status"] == 1 %}
{% if data["show_publish_btn"] %}
<script>
document.getElementById("btn-publish").addEventListener("click", function() {
document.getElementById("confirm").style.display = "block";
Expand Down
8 changes: 6 additions & 2 deletions src/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def check_instancer_perms(id):
has_perm = api_perm(["ADMIN", "SUPERADMIN", "PROBLEM_MANAGER", "CONTENT_MANAGER"])
data = db.execute("SELECT * FROM problems WHERE id=:pid", pid=problem_id)

if len(data) == 0 or (data[0]["status"] == PROBLEM_STAT["DRAFT"] and not has_perm):
needs_admin = len(data) == 0 or (data[0]["publish_timestamp"] is None or

Check warning on line 76 in src/views/api.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

W504 line break after binary operator

Check warning on line 76 in src/views/api.py

View workflow job for this annotation

GitHub Actions / build (windows-latest)

W504 line break after binary operator
parse_datetime(data[0]["publish_timestamp"]) > datetime.utcnow())
if len(data) == 0 or (needs_admin and not has_perm):
return ("Problem not found", 404)
if not data[0]["instanced"]: # Check if the problem is instanced
return ("This problem is not instanced", 400)
Expand Down Expand Up @@ -182,7 +184,9 @@ def contest_problem():
data = db.execute(("SELECT * FROM contest_problems WHERE "
"contest_id=:cid AND problem_id=:pid"),
cid=contest_id, pid=problem_id)
if len(data) == 0 or (data[0]["status"] == PROBLEM_STAT["DRAFT"] and not has_perm):
needs_admin = len(data) == 0 or (data[0]["publish_timestamp"] is None or

Check warning on line 187 in src/views/api.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

W504 line break after binary operator

Check warning on line 187 in src/views/api.py

View workflow job for this annotation

GitHub Actions / build (windows-latest)

W504 line break after binary operator
parse_datetime(data[0]["publish_timestamp"]) > datetime.utcnow())
if len(data) == 0 or (needs_admin and not has_perm):
return json_fail("Problem not found", 404)

description = read_file(f"metadata/contests/{contest_id}/{problem_id}/description.md")
Expand Down
Loading

0 comments on commit 081d15a

Please sign in to comment.