Browse Source

Merge branch 'data_migrations' into odevzdavatko

export_seznamu_prednasek
Pavel "LEdoian" Turinsky 4 years ago
parent
commit
a8f91e1222
  1. 4
      Makefile
  2. 1622
      data/sitetree_new.json
  3. 12
      fix_json.py
  4. 2
      korektury/views.py
  5. 2
      mamweb/settings_common.py
  6. 2
      mamweb/settings_prod.py
  7. BIN
      mamweb/static/images/header/beh.jpg
  8. 4
      mamweb/templates/base.html
  9. 56
      seminar/admin.py
  10. 2
      seminar/forms.py
  11. 36
      seminar/models.py
  12. BIN
      seminar/static/images/no-picture.png
  13. 2
      seminar/templates/seminar/archiv/rocnik.html
  14. 1
      seminar/templates/seminar/orgorozcestnik.html
  15. 2
      seminar/templates/seminar/profil/edit.html
  16. 2
      seminar/templates/seminar/profil/nahraj_reseni.html
  17. 2
      seminar/templates/seminar/profil/prihlaska.html
  18. 21
      seminar/templates/seminar/titulnistrana.html
  19. 6
      seminar/urls.py
  20. 1
      seminar/views/autocomplete.py
  21. 2
      seminar/views/views_all.py

4
Makefile

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

1622
data/sitetree_new.json

File diff suppressed because it is too large

12
fix_json.py

@ -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')

2
korektury/views.py

@ -186,7 +186,7 @@ class KorekturyView(generic.TemplateView):
if 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))
return

2
mamweb/settings_common.py

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

2
mamweb/settings_prod.py

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

BIN
mamweb/static/images/header/beh.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 476 KiB

4
mamweb/templates/base.html

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

56
seminar/admin.py

@ -1,11 +1,14 @@
from django.contrib import admin
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 reversion.admin import VersionAdmin
from django_reverse_admin import ReverseModelAdmin
from solo.admin import SingletonModelAdmin
# Todo: reversion
import seminar.models as m
@ -14,8 +17,6 @@ admin.site.register(m.Skola)
admin.site.register(m.Prijemce)
admin.site.register(m.Rocnik)
admin.site.register(m.Cislo)
admin.site.register(m.Organizator)
admin.site.register(m.Soustredeni)
@admin.register(m.Osoba)
class OsobaAdmin(admin.ModelAdmin):
@ -42,7 +43,14 @@ class OsobaAdmin(admin.ModelAdmin):
org.save()
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)
class ProblemAdmin(PolymorphicParentModelAdmin):
@ -74,15 +82,55 @@ class KonferaAdmin(PolymorphicChildModelAdmin):
base_model = m.Konfera
show_in_index = True
class TextAdminInline(admin.TabularInline):
model = m.Text
formfield_overrides = {
models.TextField: {'widget': widgets.TextInput}
}
exclude = ['text_zkraceny_set','text_zkraceny']
admin.site.register(m.Text)
class ResitelInline(admin.TabularInline):
model = m.Resitel
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):
model = m.PrilohaReseni
@ -92,6 +140,7 @@ admin.site.register(m.PrilohaReseni)
class Reseni_ResiteleInline(admin.TabularInline):
model = m.Reseni_Resitele
@admin.register(m.Reseni)
class ReseniAdmin(ReverseModelAdmin):
base_model = m.Reseni
@ -106,7 +155,6 @@ admin.site.register(m.Hodnoceni)
admin.site.register(m.Pohadka)
admin.site.register(m.Obrazek)
# Polymorfismus pro stromy
# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html

2
seminar/forms.py

@ -184,7 +184,7 @@ class ProfileEditForm(forms.Form):
max_value=date.today().year+8,
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)
# def clean_username(self):

36
seminar/models.py

@ -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 django.core.mail import EmailMessage
from seminar.utils import aktivniResitele
class SeminarModelBase(models.Model):
@ -624,9 +626,43 @@ class Cislo(SeminarModelBase):
return None
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):
super().save(*args, **kwargs)
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.
try:
self.cislonode.save()

BIN
seminar/static/images/no-picture.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

2
seminar/templates/seminar/archiv/rocnik.html

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

1
seminar/templates/seminar/orgorozcestnik.html

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

2
seminar/templates/seminar/profil/edit.html

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

2
seminar/templates/seminar/profil/nahraj_reseni.html

@ -1,8 +1,6 @@
{% extends "base.html" %}
{% load staticfiles %}
{% 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>
{% endblock %}

2
seminar/templates/seminar/profil/prihlaska.html

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

21
seminar/templates/seminar/titulnistrana.html

@ -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' %}
{% load humanize %}
@ -8,7 +17,17 @@
{% if nejblizsi_deadline %}
<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>
</div>
{% endif %}

6
seminar/urls.py

@ -13,8 +13,8 @@ urlpatterns = [
path('co-je-MaM/organizatori/organizovali/', views.CojemamOrganizatoriStariView.as_view(), name='stari_organizatori'),
# Archiv
path('archiv/rocniky/', views.ArchivView.as_view(), name="seninar_archiv_rocniky"),
path('archiv/temata/', views.ArchivTemataView.as_view(), name="seninar_archiv_temata"),
path('archiv/rocniky/', views.ArchivView.as_view(), name="seminar_archiv_rocniky"),
path('archiv/temata/', views.ArchivTemataView.as_view(), name="seminar_archiv_temata"),
path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'),
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'),
# 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'),
# Aesop

1
seminar/views/autocomplete.py

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

2
seminar/views/views_all.py

@ -568,6 +568,8 @@ class TitulniStranaView(generic.ListView):
try:
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:
nejblizsi_deadline = (None, None) # neni zadna aktualni deadline

Loading…
Cancel
Save