Merge branch 'data_migrations' into test
This commit is contained in:
commit
fb01c005d9
13 changed files with 136 additions and 15 deletions
File diff suppressed because one or more lines are too long
|
@ -782,5 +782,29 @@
|
|||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 40
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"access_guest": false,
|
||||
"access_loggedin": false,
|
||||
"access_perm_type": 1,
|
||||
"access_permissions": [],
|
||||
"access_restricted": false,
|
||||
"alias": null,
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"hint": "",
|
||||
"inbreadcrumbs": true,
|
||||
"inmenu": true,
|
||||
"insitetree": true,
|
||||
"parent": 1,
|
||||
"sort_order": 41,
|
||||
"title": "Odměny",
|
||||
"tree": 1,
|
||||
"url": "/o-nas/odmeny/",
|
||||
"urlaspattern": false
|
||||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 41
|
||||
}
|
||||
]
|
||||
]
|
|
@ -601,7 +601,7 @@ class Cislo(SeminarModelBase):
|
|||
if not self.titulka_nahled or os.path.getmtime(self.titulka_nahled.path) < os.path.getmtime(self.pdf.path):
|
||||
png_filename = pathlib.Path(tempfile.mkdtemp(), 'nahled.png')
|
||||
|
||||
subprocess.call([
|
||||
subprocess.run([
|
||||
"convert",
|
||||
"-density", "300x300",
|
||||
"-geometry", "{}x{}".format(VYSKA, sirka),
|
||||
|
@ -609,7 +609,10 @@ class Cislo(SeminarModelBase):
|
|||
"-flatten",
|
||||
"{}[0]".format(self.pdf.path), # titulní strana
|
||||
png_filename
|
||||
])
|
||||
],
|
||||
check=True,
|
||||
capture_output=True
|
||||
)
|
||||
|
||||
with open(png_filename,'rb') as f:
|
||||
self.titulka_nahled.save('',f,True)
|
||||
|
|
BIN
seminar/static/seminar/cross.png
Normal file
BIN
seminar/static/seminar/cross.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 717 B |
BIN
seminar/static/seminar/plus.png
Normal file
BIN
seminar/static/seminar/plus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -38,8 +38,8 @@
|
|||
<h2> Orgovské odkazy </h2>
|
||||
<ul>
|
||||
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
|
||||
<li><a href="tituly.tex">Tituly (TeX)</a></li>
|
||||
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li>
|
||||
<li><a href="tituly.tex" download>Tituly (TeX)</a></li>
|
||||
<li><a href="vysledkovka.tex" download>Výsledkovka (TeX)</a></li>
|
||||
<li><a href="obalkovani">Obálkování</a></li>
|
||||
<li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
{% if vysledkovka %}
|
||||
{% if user.je_org %}
|
||||
<div class='mam-org-only'>
|
||||
<a href='vysledkovka.tex'>Výsledkovka ročníku (LaTeX)</a>
|
||||
<a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX)</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
@ -25,8 +26,9 @@ function deleteForm(prefix, btn) {
|
|||
if (total >= 1){
|
||||
btn.closest('tr').remove();
|
||||
var forms = $('.hodnoceni');
|
||||
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
|
||||
for (var i=0, formCount=forms.length; i<formCount; i++) {
|
||||
var formCount = forms.length - 1; // There is one extra such form hidden as template!
|
||||
$('#id_' + prefix + '-TOTAL_FORMS').val(formCount);
|
||||
for (var i=0; i<formCount; i++) {
|
||||
$(forms.get(i)).find(':input').each(function() {
|
||||
updateElementIndex(this, prefix, i);
|
||||
});
|
||||
|
@ -91,21 +93,21 @@ $(document).ready(function(){
|
|||
<td>{{ subform.problem }}</td>
|
||||
<td>{{ subform.body }}</td>
|
||||
<td>{{ subform.cislo_body }}</td>
|
||||
<td><input type=button class="smazat_hodnoceni" value="Smazat" id="id_{{subform.prefix}}-jsremove"></td>
|
||||
<td><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove"><img src="{% static "seminar/cross.png" %}" alt="Smazat"></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
||||
<input type=button id="pridat_hodnoceni" value="Přidat hodnocení">
|
||||
<input type=submit></form>
|
||||
<a href="#"> <img src="{% static "seminar/plus.png" %}" id="pridat_hodnoceni" alt="Přidat hodnocení"></a> </br>
|
||||
<input type=submit value="Uložit"></form>
|
||||
|
||||
<table id="empty_form" style="display: none;">
|
||||
<tr class="hodnoceni">
|
||||
<td>{{ form.empty_form.problem }}</td>
|
||||
<td>{{ form.empty_form.body }}</td>
|
||||
<td>{{ form.empty_form.cislo_body }}</td>
|
||||
<td><input type=button class="smazat_hodnoceni" value="Smazat" id="id_{{form.empty_form.prefix}}-jsremove"></td>
|
||||
<td><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove"><img src="{% static "seminar/cross.png" %}" alt="Smazat"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
Ahoj!
|
||||
|
||||
Obdrželi jsme od Tebe žádost o obnovu hesla uživatele {{ user }} na webu M&M.
|
||||
Pro zadání nového hesla přejdi na následující stránku:
|
||||
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
|
||||
|
||||
S pozdravem,
|
||||
organizátoři M&M
|
|
@ -0,0 +1 @@
|
|||
Změna hesla na webu M&M
|
|
@ -11,6 +11,8 @@ from django.contrib.auth.models import AnonymousUser
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from enum import Enum
|
||||
|
||||
import seminar.models as m
|
||||
import seminar.treelib as t
|
||||
|
||||
|
@ -282,3 +284,58 @@ def podproblemy_v_cislu(cislo, problemy=None, hlavni_problemy=None):
|
|||
podproblemy[-1].append(problem)
|
||||
|
||||
return podproblemy
|
||||
|
||||
class TypDeadline(Enum):
|
||||
PredDeadline = auto()
|
||||
SousDeadline = auto()
|
||||
FinalDeadline = auto()
|
||||
|
||||
def deadline_v_rocniku(datum, rocnik):
|
||||
"""Funkce pro dohledání, ke kterému deadlinu daného ročníku se datum váže.
|
||||
|
||||
Vrací trojici (TypDeadline, Cislo, datumDeadline: date).
|
||||
|
||||
V případě nevalidního volání není aktuálně chování definováno(!)
|
||||
"""
|
||||
cisla = m.Cislo.objects.filter(rocnik=rocnik)
|
||||
deadliny = []
|
||||
for c in cisla:
|
||||
if c.datum_preddeadline is not None:
|
||||
deadliny.append((TypDeadline.PredDeadline, c, c.datum_preddeadline))
|
||||
if c.datum_deadline_soustredeni is not None:
|
||||
deadliny.append((TypDeadline.SousDeadline, c, c.datum_deadline_soustredeni))
|
||||
if c.datum_deadline is not None:
|
||||
deadliny.append((TypDeadline.FinalDeadline, c, c.datum_deadline))
|
||||
deadliny = sorted(deadliny, key=lambda x: x[2]) # podle data
|
||||
for dl in deadliny:
|
||||
if datum <= dl:
|
||||
# První takový deadline je ten nejtěsnější
|
||||
return dl
|
||||
|
||||
def deadline(datum):
|
||||
"""Funkce pro dohledání, ke kterému deadlinu se datum váže.
|
||||
|
||||
Vrací trojici (TypDeadline, Cislo, datumDeadline: date).
|
||||
"""
|
||||
|
||||
rok = datum.year
|
||||
# Dva ročníky podezřelé z obsahování dat
|
||||
pozdejsi_rocnik = m.Rocnik.filter(prvni_rok=rok)
|
||||
drivejsi_rocnik = m.Rocnik.filter(druhy_rok=rok)
|
||||
if any(
|
||||
pozdejsi_rocnik.count() > 1,
|
||||
drivejsi_rocnik.count() > 1,
|
||||
):
|
||||
raise ValueError(f"Více ročníků začíná/končí stejným rokem: {rok}")
|
||||
pozdejsi_rocnik = pozdejsi_rocnik.first() if pozdejsi_rocnik.count() > 0 else None
|
||||
drivejsi_rocnik = drivejsi_rocnik.first() if drivejsi_rocnik.count() > 0 else None
|
||||
|
||||
# Předpokládáme, že neexistuje číslo, které má deadline ale nemá finální deadline.
|
||||
posledni_deadline_drivejsiho_rocniku = m.Cislo.objects.get(rocnik=drivejsi_rocnik, datum_deadline__isnull=False).datum_deadline
|
||||
|
||||
if datum <= posledni_deadline_drivejsiho_rocniku:
|
||||
return deadline_v_rocniku(datum, drivejsi_rocnik)
|
||||
else:
|
||||
return deadline_v_rocniku(datum, pozdejsi_rocnik)
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404, render, redirect
|
|||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
||||
from django.urls import reverse,reverse_lazy
|
||||
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
|
||||
from django.core.mail import send_mail
|
||||
from django.views import generic
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect
|
||||
|
@ -1057,6 +1058,21 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
|
|||
|
||||
prilohy.instance = self.object
|
||||
prilohy.save()
|
||||
|
||||
# Pošleme mail opravovatelům a garantovi
|
||||
# FIXME: Nechat spočítat databázi? Je to pár dotazů (pravděpodobně), takže to za to možná nestojí
|
||||
prijemci = set()
|
||||
for prob in form.cleaned_data['problem']:
|
||||
prijemci.update(prob.opravovatele.all())
|
||||
prijemci.add(prob.garant)
|
||||
# FIXME: Možná poslat mail i relevantním orgům nadproblémů?
|
||||
# FIXME: Víc informativní obsah mailů, možná vč. příloh?
|
||||
send_mail(
|
||||
subject="Nové řešení k problému",
|
||||
message=f"Řešitel poslal řešení...",
|
||||
from_email="submitovatko@mam.mff.cuni.cz", # FIXME: Chceme to mít radši tady, nebo v nastavení?
|
||||
recipient_list=list(prijemci),
|
||||
)
|
||||
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
|
@ -1223,6 +1239,8 @@ class PasswordResetView(auth_views.PasswordResetView):
|
|||
# TODO: vlastní email_template_name a subject_template_name a html_email_template_name
|
||||
success_url = reverse_lazy('reset_password_done')
|
||||
from_email = 'login@mam.mff.cuni.cz'
|
||||
email_template_name = 'seminar/registrace/password_reset_email.html'
|
||||
subject_template_name = 'seminar/registrace/password_reset_subject.txt'
|
||||
|
||||
class PasswordResetDoneView(auth_views.PasswordResetDoneView):
|
||||
""" Poslali jsme e-mail (pokud bylo kam)). """
|
||||
|
|
|
@ -4,6 +4,8 @@ from seminar.utils import aktivniResitele, resi_v_rocniku, cisla_rocniku, hlavni
|
|||
import time
|
||||
### Výsledky
|
||||
|
||||
ROCNIK_ZRUSENI_TEMAT = 25
|
||||
|
||||
def sloupec_s_poradim(setrizene_body):
|
||||
"""
|
||||
Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník
|
||||
|
@ -255,7 +257,10 @@ def secti_body_za_cislo(cislo, aktivni_resitele, hlavni_problemy=None):
|
|||
inst = problem.get_real_instance()
|
||||
return not(isinstance(inst, m.Clanek) or isinstance(inst, m.Konfera))
|
||||
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
if cislo.rocnik.rocnik < ROCNIK_ZRUSENI_TEMAT:
|
||||
temata_a_spol = hlavni_problemy
|
||||
else:
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
|
||||
hlavni_problemy_slovnik = {}
|
||||
for hp in temata_a_spol:
|
||||
|
@ -410,7 +415,10 @@ def vysledkovka_cisla(cislo, context=None):
|
|||
|
||||
return not(isinstance(problem.get_real_instance(), m.Clanek) or isinstance(problem.get_real_instance(), m.Konfera))
|
||||
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
if cislo.rocnik.rocnik < ROCNIK_ZRUSENI_TEMAT:
|
||||
temata_a_spol = hlavni_problemy
|
||||
else:
|
||||
temata_a_spol = list(filter(ne_clanek_ne_konfera, hlavni_problemy))
|
||||
|
||||
# získáme body u jednotlivých témat
|
||||
podproblemy = podproblemy_v_cislu(cislo, problemy, temata_a_spol)
|
||||
|
|
Loading…
Reference in a new issue