Merge branch 'data_migrations' into odevzdavatko

This commit is contained in:
Pavel "LEdoian" Turinsky 2021-01-26 21:05:05 +01:00
commit a8f91e1222
21 changed files with 946 additions and 835 deletions

View file

@ -34,8 +34,8 @@ install_web: venv_check
pip install --upgrade setuptools pip install --upgrade setuptools
# Instalace závislostí webu # Instalace závislostí webu
pip install -r requirements.txt --upgrade pip install -r requirements.txt --upgrade
# Po vygenerování testdat spusť ./manage.py loaddata sitetree_new.json, ať máš menu # Po vygenerování testdat spusť ./manage.py loaddata data/*, ať máš menu a další modely
# Pro synchronizaci flatpages spusť make sync_prod_flatpages :x
install_venv: install_venv:
${VENV} ${VENV_PATH} ${VENV} ${VENV_PATH}

File diff suppressed because it is too large Load diff

12
fix_json.py Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/python3
import json
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("input", type=argparse.FileType('r', encoding='utf-8'))
parser.add_argument('output', type=argparse.FileType('w', encoding='utf-8'))
args = parser.parse_args()
data = json.load(args.input)
json.dump(data, args.output, ensure_ascii=False, sort_keys=True, indent='\t')

View file

@ -186,7 +186,7 @@ class KorekturyView(generic.TemplateView):
if email: if email:
emails.discard(email) emails.discard(email)
if not settings.SEND_EMAIL_NOTIFICATIONS: if not settings.POSLI_MAILOVOU_NOTIFIKACI:
print("Poslal bych upozornění na tyto adresy: ", " ".join(emails)) print("Poslal bych upozornění na tyto adresy: ", " ".join(emails))
return return

View file

@ -308,4 +308,4 @@ CISLO_IMG_DIR = os.path.join('cislo', 'img')
# E-MAIL NOTIFICATIONS # E-MAIL NOTIFICATIONS
SEND_EMAIL_NOTIFICATIONS = False POSLI_MAILOVOU_NOTIFIKACI = False

View file

@ -66,4 +66,4 @@ LOGGING['handlers']['registration_error_log']['filename'] = '/home/mam-web/logs/
# E-MAIL NOTIFICATIONS # E-MAIL NOTIFICATIONS
SEND_EMAIL_NOTIFICATIONS = True POSLI_MAILOVOU_NOTIFIKACI = True

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 476 KiB

View file

@ -31,6 +31,10 @@
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script> </script>
{# Případné skripty widgetů formulářů #}
{% if form %}
{{form.media}}
{% endif %}
{# script specifický pro stránku #} {# script specifický pro stránku #}
{% block script %}{% endblock %} {% block script %}{% endblock %}

View file

@ -1,11 +1,14 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.db import models
from django.forms import widgets
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from django_reverse_admin import ReverseModelAdmin from django_reverse_admin import ReverseModelAdmin
from solo.admin import SingletonModelAdmin from solo.admin import SingletonModelAdmin
# Todo: reversion # Todo: reversion
import seminar.models as m import seminar.models as m
@ -14,8 +17,6 @@ admin.site.register(m.Skola)
admin.site.register(m.Prijemce) admin.site.register(m.Prijemce)
admin.site.register(m.Rocnik) admin.site.register(m.Rocnik)
admin.site.register(m.Cislo) admin.site.register(m.Cislo)
admin.site.register(m.Organizator)
admin.site.register(m.Soustredeni)
@admin.register(m.Osoba) @admin.register(m.Osoba)
class OsobaAdmin(admin.ModelAdmin): class OsobaAdmin(admin.ModelAdmin):
@ -42,7 +43,14 @@ class OsobaAdmin(admin.ModelAdmin):
org.save() org.save()
udelej_orgem.short_description = "Udělej vybraných osob organizátory" udelej_orgem.short_description = "Udělej vybraných osob organizátory"
@admin.register(m.Organizator)
class OrganizatorAdmin(admin.ModelAdmin):
search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'prezdivka']
@admin.register(m.Resitel)
class ResitelAdmin(admin.ModelAdmin):
search_fields = ['jmeno', 'prijmeni', 'prezdivka']
ordering = ('osoba__jmeno','osoba__prijmeni')
@admin.register(m.Problem) @admin.register(m.Problem)
class ProblemAdmin(PolymorphicParentModelAdmin): class ProblemAdmin(PolymorphicParentModelAdmin):
@ -74,15 +82,55 @@ class KonferaAdmin(PolymorphicChildModelAdmin):
base_model = m.Konfera base_model = m.Konfera
show_in_index = True show_in_index = True
class TextAdminInline(admin.TabularInline): class TextAdminInline(admin.TabularInline):
model = m.Text model = m.Text
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
exclude = ['text_zkraceny_set','text_zkraceny'] exclude = ['text_zkraceny_set','text_zkraceny']
admin.site.register(m.Text) admin.site.register(m.Text)
class ResitelInline(admin.TabularInline): class ResitelInline(admin.TabularInline):
model = m.Resitel model = m.Resitel
extra = 1 extra = 1
admin.site.register(m.Resitel)
class SoustredeniUcastniciInline(admin.TabularInline):
model = m.Soustredeni_Ucastnici
extra = 1
fields = ['resitel','poznamka']
autocomplete_fields = ['resitel']
ordering = ['resitel__osoba__jmeno', 'resitel__osoba__prijmeni']
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
def get_queryset(self,request):
qs = super().get_queryset(request)
return qs.select_related('resitel','soustredeni')
class SoustredeniOrganizatoriInline(admin.TabularInline):
model = m.Soustredeni.organizatori.through
extra = 1
fields = ['organizator','poznamka']
autocomplete_fields = ['organizator']
ordering = ['organizator__osoba__jmeno','organizator__prijmeni']
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
def get_queryset(self,request):
qs = super().get_queryset(request)
return qs.select_related('organizator', 'soustredeni')
@admin.register(m.Soustredeni)
class SoustredeniAdmin(admin.ModelAdmin):
model = m.Soustredeni
inline_type = 'tabular'
inlines = [SoustredeniUcastniciInline, SoustredeniOrganizatoriInline]
class PrilohaReseniInline(admin.TabularInline): class PrilohaReseniInline(admin.TabularInline):
model = m.PrilohaReseni model = m.PrilohaReseni
@ -92,6 +140,7 @@ admin.site.register(m.PrilohaReseni)
class Reseni_ResiteleInline(admin.TabularInline): class Reseni_ResiteleInline(admin.TabularInline):
model = m.Reseni_Resitele model = m.Reseni_Resitele
@admin.register(m.Reseni) @admin.register(m.Reseni)
class ReseniAdmin(ReverseModelAdmin): class ReseniAdmin(ReverseModelAdmin):
base_model = m.Reseni base_model = m.Reseni
@ -106,7 +155,6 @@ admin.site.register(m.Hodnoceni)
admin.site.register(m.Pohadka) admin.site.register(m.Pohadka)
admin.site.register(m.Obrazek) admin.site.register(m.Obrazek)
# Polymorfismus pro stromy # Polymorfismus pro stromy
# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html

View file

@ -184,7 +184,7 @@ class ProfileEditForm(forms.Form):
max_value=date.today().year+8, max_value=date.today().year+8,
required=True) required=True)
zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True) zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat email s upozorněním na vydání nového čísla', required=True) zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat email s upozorněním na vydání nového čísla', required=False)
spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False) spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
# def clean_username(self): # def clean_username(self):

View file

@ -31,6 +31,8 @@ from unidecode import unidecode # Používám pro získání ID odkazu (ještě
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
from django.core.mail import EmailMessage
from seminar.utils import aktivniResitele
class SeminarModelBase(models.Model): class SeminarModelBase(models.Model):
@ -624,9 +626,43 @@ class Cislo(SeminarModelBase):
return None return None
return c return c
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__original_verejne = self.verejne_db
def posli_cislo_mailem(self):
# parametry e-mailu
odkaz = self.get_absolute_url()
poslat_z_mailu = 'zadani@mam.mff.cuni.cz'
predmet = 'Vyšlo číslo {}'.format(self.kod())
text_mailu = 'Ahoj,\n' \
'na adrese {} najdete nejnovější číslo.\n' \
'Vaše M&M\n'.format(odkaz)
# Prijemci e-mailu
emaily = map(lambda r: r.osoba.email, filter(lambda r: r.zasilat_cislo_emailem, aktivniResitele(self)))
if not settings.POSLI_MAILOVOU_NOTIFIKACI:
print("Poslal bych upozornění na tyto adresy: ", " ".join(emaily))
return
email = EmailMessage(
subject=predmet,
body=text_mailu,
from_email=poslat_z_mailu,
bcc=list(emaily)
#bcc = příjemci skryté kopie
)
email.send()
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super().save(*args, **kwargs) super().save(*args, **kwargs)
self.vygeneruj_nahled() self.vygeneruj_nahled()
# Při zveřejnění pošle mail
if self.verejne_db and not self.__original_verejne:
self.posli_cislo_mailem()
# *Node.save() aktualizuje název *Nodu. # *Node.save() aktualizuje název *Nodu.
try: try:
self.cislonode.save() self.cislonode.save()

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -32,7 +32,7 @@
{% if c.titulka_nahled %} {% if c.titulka_nahled %}
<img src="{{ c.titulka_nahled.url }}" alt="{{ c.kod }}" height=180px> <img src="{{ c.titulka_nahled.url }}" alt="{{ c.kod }}" height=180px>
{% else %} {% else %}
<img src="" alt="no image" height=180px> {% load static %} <img src="{% static 'images/no-picture.png' %}" height=180px alt="no-picture">
{% endif %} {% endif %}
</div> </div>

View file

@ -58,6 +58,7 @@
<h2><strong>Soustředění</strong></h2> <h2><strong>Soustředění</strong></h2>
<ul> <ul>
<li><a href="/admin/seminar/soustredeni/add/">přidat soustředění</a></li>
<li><strong>přednášky</strong> <li><strong>přednášky</strong>
<ul> <ul>

View file

@ -2,8 +2,6 @@
{% load staticfiles %} {% load staticfiles %}
{% block script %} {% block script %}
<!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!-->
{{form.media}}
<script src="{% static 'seminar/prihlaska.js' %}"></script> <script src="{% static 'seminar/prihlaska.js' %}"></script>
{% endblock %} {% endblock %}

View file

@ -1,8 +1,6 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load staticfiles %} {% load staticfiles %}
{% block script %} {% block script %}
<!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!-->
{{form.media}}
<script src="{% static 'seminar/dynamic_formsets.js' %}"></script> <script src="{% static 'seminar/dynamic_formsets.js' %}"></script>
{% endblock %} {% endblock %}

View file

@ -2,8 +2,6 @@
{% load staticfiles %} {% load staticfiles %}
{% block script %} {% block script %}
<!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!-->
{{form.media}}
<script src="{% static 'seminar/prihlaska.js' %}"></script> <script src="{% static 'seminar/prihlaska.js' %}"></script>
{% endblock %} {% endblock %}

View file

@ -1,3 +1,12 @@
<script>
function preddeadline() {
alert("Řešení, která nám přijdou do tohoto deadlinu, se pokusíme opravit co nejdříve, abyste měli ještě šanci si je ještě opravit před definitivním deadlinem čísla.");
}
function sousdeadline() {
alert("Body za řešení, která nám přijdou do tohoto deadlinu, se ještě započítají pro účast na připravovaném soustředění.");
}
</script>
{% extends 'base.html' %} {% extends 'base.html' %}
{% load humanize %} {% load humanize %}
@ -8,7 +17,17 @@
{% if nejblizsi_deadline %} {% if nejblizsi_deadline %}
<div class="odpocet"> <div class="odpocet">
<p><b><big>Do konce <a href="/zadani/aktualni/">odeslání řešení</a> {% if typ_deadline == 'soustredeni' %}(pro účast na soustředění) {% elif typ_deadline == 'preddeadline' %}(pro otištění došlých řešení) {% endif %}zbývá: <p><b><big>Do
{% if typ_deadline == 'soustredeni' %}
<a href="" onClick="sousdeadline()"
title="Body za řešení, která nám přijdou do tohoto deadlinu, se ještě započítají pro účast na připravovaném soustředění.">
deadlinu</a> odeslání <a href="/zadani/aktualni/">řešení
</a> pro účast na soustředění
{% elif typ_deadline == 'preddeadline' %} <a href="" onClick="preddeadline()"
title="Řešení, která nám přijdou do tohoto deadlinu, se pokusíme opravit co nejdříve, abyste měli ještě šanci si je ještě opravit před definitivním deadlinem čísla.">1. deadlinu</a> aktuálního <a href="/zadani/aktualni/">čísla</a>
{% else %} deadlinu aktuálního <a href="/zadani/aktualni/">čísla</a>
{% endif %}zbývá:
{{nejblizsi_deadline|timeuntil}}</big></b></p> {{nejblizsi_deadline|timeuntil}}</big></b></p>
</div> </div>
{% endif %} {% endif %}

View file

@ -13,8 +13,8 @@ urlpatterns = [
path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'), path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'),
# Archiv # Archiv
path('archiv/rocniky/', views.ArchivView.as_view(), name="seninar_archiv_rocniky"), path('archiv/rocniky/', views.ArchivView.as_view(), name="seminar_archiv_rocniky"),
path('archiv/temata/', views.ArchivTemataView.as_view(), name="seninar_archiv_temata"), path('archiv/temata/', views.ArchivTemataView.as_view(), name="seminar_archiv_temata"),
path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'),
path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'),
@ -63,7 +63,7 @@ urlpatterns = [
path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'),
# Clanky # Clanky
path('clanky/resitel/', views.ClankyResitelView.as_view(), name='clanky_resitel'), path('archiv/clanky/', views.ClankyResitelView.as_view(), name='clanky_resitel'),
#path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), #path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'),
# Aesop # Aesop

View file

@ -1,5 +1,6 @@
from dal import autocomplete from dal import autocomplete
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.db.models import Q
import seminar.models as m import seminar.models as m
from .helpers import LoginRequiredAjaxMixin from .helpers import LoginRequiredAjaxMixin

View file

@ -568,6 +568,8 @@ class TitulniStranaView(generic.ListView):
try: try:
nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0] nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0]
if nejblizsi_deadline[0] == deadline_soustredeni[0]:
nejblizsi_deadline = deadline_soustredeni
except IndexError: except IndexError:
nejblizsi_deadline = (None, None) # neni zadna aktualni deadline nejblizsi_deadline = (None, None) # neni zadna aktualni deadline