Skip to content
Snippets Groups Projects

Nastavení kol a úloh

Merged
Jiří Setničkarequested to merge
jirka/manage_round into devel
1 open thread
1 file
+ 23
4
Compare changes
  • Side-by-side
  • Inline
+ 40
129
@@ -42,7 +42,7 @@ class ParticipantsFilterForm(PagerForm):
class ParticipantsActionForm(FlaskForm):
action_on = wtforms.RadioField(
"Provést akci na", validators=[validators.DataRequired()],
choices=[('all', 'všech vyfiltrovaných soutěžících'), ('checked', 'označených soutěžících')]
choices=[('all', 'všech vyfiltrovaných účastnících'), ('checked', 'označených účastnících')]
# checkboxes are handled not through FlaskForm, see below
)
@@ -64,9 +64,9 @@ class ParticipantsActionForm(FlaskForm):
def do_action(self, round: db.Round, rights: mo.rights.Rights, query: Query) -> bool:
"""Do participation modification on partipations from given query
(possibly filtered by checkboxes). Expects that rights for round/contest
are checked before calling this function, `rights` param are used only
for checking that we can move participation to another contest."""
(possibly filtered by checkboxes). `rights` param is used to check rights
for contest of each modified participation or for contest in which
participation is moved to."""
if not self.validate_on_submit():
return False
@@ -92,7 +92,8 @@ class ParticipantsActionForm(FlaskForm):
return False
rights.get_for_contest(contest)
if not rights.have_right(mo.rights.Right.manage_contest):
flash(f"Nemáte právo ke správě soutěže v kole {round.round_code()} v oblasti {contest_place.name}, nelze do ní přesunout soutěžící", 'danger')
flash(f"Nemáte právo ke správě soutěže v kole {round.round_code()} v oblasti {contest_place.name}, nelze do ní přesunout účastníky", 'danger')
return False
elif self.remove_participation.data:
pass
else:
@@ -105,8 +106,26 @@ class ParticipantsActionForm(FlaskForm):
flash('Data v checkboxech nelze převést na čísla, kontaktujte správce', 'danger')
return False
count = 0
# Check all participations if we can edit them
ctants = query.all()
rights_cache = set()
for pion, _, _ in ctants:
u = pion.user
if self.action_on.data == 'checked' and u.user_id not in user_ids:
continue
if pion.contest_id in rights_cache:
continue
rights.get_for_contest(pion.contest)
if rights.have_right(mo.rights.Right.manage_contest):
rights_cache.add(pion.contest_id)
continue
flash(
f"Nemáte právo ke správě soutěže v kole {round.round_code()} v oblasti {pion.contest.place.name} "
+ f"(účastník {u.first_name} {u.last_name}). Žádná akce nebyla provedena.", 'danger'
)
return False
count = 0
for pion, _, _ in ctants:
u = pion.user
if self.action_on.data == 'checked' and u.user_id not in user_ids:
@@ -140,130 +159,19 @@ class ParticipantsActionForm(FlaskForm):
sess.commit()
if count == 0:
flash('Žádní vybraní soutěžící', 'warning')
flash('Žádní vybraní účastníci', 'warning')
elif self.set_participation_state.data:
flash(f'Nastaven stav {db.part_state_names[self.participation_state.data]} {count} řešitelům', 'success')
flash(f'Nastaven stav {db.part_state_names[self.participation_state.data]} {count} účastníkům', 'success')
elif self.set_participation_place.data:
flash(f'Nastaveno soutěžní místo {participation_place.name} {count} řešitelům', 'success')
flash(f'Nastaveno soutěžní místo {participation_place.name} {count} účastníkům', 'success')
elif self.set_contest.data:
flash(f'{count} řešitelů přesunuto do soutěže v oblasti {contest_place.name}', 'success')
flash(f'{count} účastníků přesunuto do soutěže v oblasti {contest_place.name}', 'success')
elif self.remove_participation.data:
flash(f'Odstraněno {count} soutěžících z této soutěže', 'success')
flash(f'Odstraněno {count} účastníků z této soutěže', 'success')
return True
@app.route('/org/contest/')
def org_contest_root():
sess = db.get_session()
rounds = sess.query(db.Round).filter_by(year=mo.current_year).order_by(db.Round.year, db.Round.category, db.Round.seq)
return render_template('org_contest_root.html', rounds=rounds, level_names=mo.db.place_level_names)
def get_round(id: int) -> db.Round:
round = db.get_session().query(db.Round).get(id)
if not round:
raise werkzeug.exceptions.NotFound()
return round
def get_round_rr(id: int, right_needed: Optional[mo.rights.Right]) -> Tuple[db.Round, mo.rights.Rights]:
round = get_round(id)
rr = mo.rights.Rights(g.user)
rr.get_for_round(round)
if not (right_needed is None or rr.have_right(right_needed)):
raise werkzeug.exceptions.Forbidden()
return round, rr
@app.route('/org/contest/r/<int:id>/')
def org_round(id: int):
sess = db.get_session()
round, rr = get_round_rr(id, None)
contests = (sess.query(db.Contest)
.filter_by(round=round)
.options(joinedload(db.Contest.place))
.all())
contests.sort(key=lambda c: locale.strxfrm(c.place.name))
return render_template(
'org_round.html',
round=round,
contests=contests,
level_names=mo.db.place_level_names,
can_manage=rr.have_right(mo.rights.Right.manage_contest),
)
@app.route('/org/contest/r/<int:id>/list', methods=('GET', 'POST'))
def org_round_list(id: int):
round, rr = get_round_rr(id, mo.rights.Right.manage_contest)
format = request.args.get('format', "")
filter = ParticipantsFilterForm(request.args)
filter.validate()
query = get_contestants_query(
round=round,
school=db.get_place_by_code(filter.school.data),
contest_place=db.get_place_by_code(filter.contest_place.data),
participation_place=db.get_place_by_code(filter.participation_place.data),
participation_state=None if filter.participation_state.data == '*' else filter.participation_state.data
)
action_form = ParticipantsActionForm()
if action_form.do_action(round=round, rights=rr, query=query):
# Action happened, redirect
return redirect(request.url)
(count, query) = filter.apply_limits(query, pagesize=50)
# count = query.count()
if format == "":
table = make_contestant_table(query, add_contest_column=True, add_checkbox=True)
return render_template(
'org_round_list.html',
round=round,
table=table,
filter=filter, count=count, action_form=action_form,
)
else:
table = make_contestant_table(query)
return table.send_as(format)
@app.route('/org/contest/r/<int:id>/import', methods=('GET', 'POST'))
def org_round_import(id: int):
round, rr = get_round_rr(id, mo.rights.Right.manage_contest)
form = ImportForm()
errs = []
if form.validate_on_submit():
tmp_name = secrets.token_hex(16) + '.csv'
tmp_path = os.path.join(app.instance_path, 'imports', tmp_name)
form.file.data.save(tmp_path)
imp = mo.imports.Import(g.user)
if imp.import_contest(round, None, tmp_path):
flash(f'Účastníci importováni (založeno {imp.cnt_new_users} uživatelů, {imp.cnt_new_participations} účastí)', 'success')
return redirect(url_for('org_round', id=round.round_id))
else:
flash('Došlo k chybě při importu (detaily níže)', 'danger')
errs = imp.errors
return render_template(
'org_round_import.html',
round=round,
form=form,
errs=errs,
)
def get_contest(id: int) -> db.Contest:
contest = (db.get_session().query(db.Contest)
.options(joinedload(db.Contest.place),
@@ -274,7 +182,7 @@ def get_contest(id: int) -> db.Contest:
return contest
def get_contest_rr(id: int, right_needed: Optional[mo.rights.Right]) -> Tuple[db.Contest, mo.rights.Rights]:
def get_contest_rr(id: int, right_needed: Optional[mo.rights.Right] = None) -> Tuple[db.Contest, mo.rights.Rights]:
contest = get_contest(id)
rr = mo.rights.Rights(g.user)
@@ -340,7 +248,8 @@ def org_contest_import_template():
@app.route('/org/contest/c/<int:id>/ucastnici', methods=('GET', 'POST'))
def org_contest_list(id: int):
contest, rr = get_contest_rr(id, mo.rights.Right.manage_contest)
contest, rr = get_contest_rr(id)
can_edit = rr.have_right(mo.rights.Right.manage_contest)
format = request.args.get('format', "")
filter = ParticipantsFilterForm(request.args)
@@ -353,6 +262,8 @@ def org_contest_list(id: int):
participation_state=None if filter.participation_state.data == '*' else filter.participation_state.data
)
action_form = None
if can_edit:
action_form = ParticipantsActionForm()
if action_form.do_action(round=contest.round, rights=rr, query=query):
# Action happened, redirect
@@ -362,7 +273,7 @@ def org_contest_list(id: int):
count = query.count()
if format == "":
table = make_contestant_table(query, add_checkbox=True)
table = make_contestant_table(query, add_checkbox=can_edit)
return render_template(
'org_contest_list.html',
contest=contest,
Loading