Skip to content
Snippets Groups Projects
Commit 6c24f402 authored by Jiří Setnička's avatar Jiří Setnička
Browse files

Zprávičky: Editace z nastavení kola

parent e56c4862
Branches
No related tags found
1 merge request!57Zprávičky
from flask import render_template, g, redirect, url_for, flash, request
import locale
from flask_wtf.form import FlaskForm
import bleach
from bleach.sanitizer import ALLOWED_TAGS
import markdown
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from sqlalchemy.sql.functions import coalesce
......@@ -428,6 +431,7 @@ class RoundEditForm(FlaskForm):
"Hranice bodů pro úspěšné řešitele", validators=[validators.Optional()],
description="Řešitelé s alespoň tolika body budou označeni za úspěšné řešitele, prázdná hodnota = žádné neoznačovat",
)
has_messages = wtforms.BooleanField("Zprávičky pro účastníky (aktivuje možnost vytvářet novinky zobrazované účastníkům)")
submit = wtforms.SubmitField('Uložit')
def validate_state(self, field):
......@@ -489,3 +493,78 @@ def org_task_statement(id: int):
raise werkzeug.exceptions.Forbidden()
return mo.web.util.send_task_statement(round)
class MessageAddForm(FlaskForm):
title = wtforms.StringField('Nadpis', validators=[validators.Required()])
markdown = wtforms.TextAreaField(
'Text novinky', description='Zprávičky lze formátovat pomocí Markdownu',
validators=[validators.Required()],
render_kw={'rows': 10},
)
submit = wtforms.SubmitField(label='Vložit zprávičku')
preview = wtforms.SubmitField(label='Zobrazit náhled')
class MessageRemoveForm(FlaskForm):
message_id = wtforms.IntegerField(validators=[validators.Required()])
message_remove = wtforms.SubmitField()
@app.route('/org/contest/r/<int:id>/messages/', methods=('GET', 'POST'))
def org_round_messages(id: int):
sess = db.get_session()
round, _, rr = get_round_rr(id, None, True)
if not round.has_messages:
flash('Toto kolo nemá aktivní zprávičky pro účastníky, aktivujte je v nastavení kola', 'warning')
return redirect(url_for('org_round', id=id))
messages = sess.query(db.Message).filter_by(round_id=id).order_by(db.Message.created_at).all()
add_form: Optional[MessageAddForm] = None
remove_form: Optional[MessageRemoveForm] = None
preview: Optional[db.Message] = None
if rr.have_right(Right.manage_round):
add_form = MessageAddForm()
remove_form = MessageRemoveForm()
if remove_form.validate_on_submit() and remove_form.message_remove.data:
msg = sess.query(db.Message).get(remove_form.message_id.data)
if not msg or msg.round_id != id:
raise werkzeug.exceptions.NotFound()
sess.delete(msg)
sess.commit()
app.logger.info(f"Zprávička pro kolo {id} odstraněna: {db.row2dict(msg)}")
flash('Zprávička odstraněna', 'success')
return redirect(url_for('org_round_messages', id=id))
if add_form.validate_on_submit():
msg = db.Message(
round_id=id,
created_by=g.user.user_id,
created_at=mo.now,
)
add_form.populate_obj(msg)
msg.html = bleach.clean(
markdown.markdown(msg.markdown),
tags=ALLOWED_TAGS+['p']
)
if add_form.preview.data:
preview = msg
elif add_form.submit.data:
sess.add(msg)
sess.commit()
app.logger.info(f"Vložena nová zprávička pro kolo {id}: {db.row2dict(msg)}")
flash('Zprávička úspěšně vložena', 'success')
return redirect(url_for('org_round_messages', id=id))
return render_template(
'org_round_messages.html',
round=round, rr=rr, messages=messages,
add_form=add_form, remove_form=remove_form,
preview=preview,
)
......@@ -58,6 +58,9 @@
{% if can_manage_round %}
<a class="btn btn-default" href='{{ url_for('org_round_edit', id=round.round_id) }}'>Editovat nastavení kola</a>
{% endif %}
{% if round.has_messages %}
<a class="btn btn-default" href='{{ url_for('org_round_messages', id=round.round_id) }}'>Zprávičky</a>
{% endif %}
{% if g.user.is_admin %}
<a class="btn btn-default" href='{{ log_url('round', round.round_id) }}'>Historie</a>
{% endif %}
......
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}{{ round.name }} {{ round.round_code() }} – zprávičky{% endblock %}
{% block breadcrumbs %}
{{ contest_breadcrumbs(round=round, action='Zprávičky') }}
{% endblock %}
{% block body %}
{% if messages %}
{% with message_remove_form=remove_form %}
{% include "parts/messages.html" %}
{% endwith %}
{% else %}<p><i>Žádné zprávičky k vypsání.</i></p>{% endif %}
{% if add_form %}
<h3>Nová zprávička</h3>
<div class="form-frame">
{{ wtf.quick_form(add_form, button_map={'submit': 'primary', 'preview': 'default'}) }}
</div>
{% if preview %}
<div class="form-frame">
<b>Náhled zprávičky:</b>
{% with messages = [preview] %}
{% include "parts/messages.html" %}
{% endwith %}
</div>
{% endif %}
{% else %}
<p><i>Nemáte právo k přidávání nových zpráviček.</i></p>
{% endif %}
{% endblock %}
{% for msg in messages %}
<div class="message">
<span class="msg-title">{{ msg.title }}</span>
<span class="msg-date">{{ msg.created_at|time_and_timedelta }}</span>
<div class="msg-text">{{ msg.html|safe }}</div>
{% if message_remove_form %}
<form method="POST" onsubmit="return confirm('Opravdu nenávratně smazat?');" style="float: right; margin-top: -20px;">
{{ message_remove_form.csrf_token }}
<input type="hidden" name="message_id" value="{{ msg.message_id }}">
<input type="submit" name="message_remove" class="btn btn-xs btn-danger" value="Smazat">
</form>
{% endif %}
</div>
{% endfor %}
......@@ -382,3 +382,24 @@ div.alert + div.alert {
.collapsible input[type="checkbox"].toggle:checked ~ .collapsible-inner {
max-height: 100vh;
}
div.message {
padding: 5px 10px;
margin-bottom: 5px;
border-radius: 5px;
border: solid 1px #f8d99b;
color:#46381f;
background-color:#fff8d5;
}
div.message.new {
background-color: #ffdede;
border: solid 1px #ff5e5e;
}
div.message .msg-title {
font-weight: bold;
}
div.message .msg-date {
float: right;
font-style: italic;
color: #777;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment