diff --git a/Makefile b/Makefile
index e755aa55..17a4847f 100644
--- a/Makefile
+++ b/Makefile
@@ -117,10 +117,10 @@ sync_test: sync_test_media sync_test_db
# Does not sync Galerie and CACHE (too huge).
sync_local_media:
rsync -ave ssh --exclude Galerie --exclude CACHE\
- atrey.karlin.mff.cuni.cz:/akce/MaM/WWW/mamweb-prod/media/ ./media/
+ www-mam@atrey.karlin.mff.cuni.cz:/akce/MaM/WWW/mamweb-prod/media/ ./media/
# Downloads and restores production database to local database. PostgreSQL only.
sync_local_db:
- scp atrey.karlin.mff.cuni.cz:`ssh atrey.karlin.mff.cuni.cz 'ls -v /akce/MaM/WWW/backups/mam-prod-*\.pgdump | tail -n 1'` \
+ scp www-mam@atrey.karlin.mff.cuni.cz:`ssh www-mam@atrey.karlin.mff.cuni.cz 'ls -v /akce/MaM/WWW/backups/mam-prod-*\.pgdump | tail -n 1'` \
./last.pgdump
pg_restore -c -d mam -U mam last.pgdump
diff --git a/_git_hooks/README.md b/_git_hooks/README.md
new file mode 100644
index 00000000..e74e5c53
--- /dev/null
+++ b/_git_hooks/README.md
@@ -0,0 +1,16 @@
+git hooks
+=========
+
+Kontrola stylu pythoních zdrojáků pomocí flake8. Kontrolujeme jen změny,
+abychom nenutili lidi dělat nesouvisející úpravy, které by rozbíjely historii
+(git blame).
+
+pre-commit
+----------
+* kontrola změn před commitnutím
+* instalace: lokálně zkopírovat do .git/hooks (musí být spustitelný)
+
+update
+------
+* kontrola změn přicházejících s pushem
+* instalace: na atreyi zkopírovat do /akce/MaM/MaMweb/mamweb.git/hooks
diff --git a/_git_hooks/pre-commit b/_git_hooks/pre-commit
new file mode 100755
index 00000000..bdea5060
--- /dev/null
+++ b/_git_hooks/pre-commit
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# Git hook script to verify what is about to be committed.
+# Checks that the changes don't introduce new flake8 errors.
+
+git diff --unified=1 --cached HEAD -- '*py' | flake8 --diff
diff --git a/_git_hooks/update b/_git_hooks/update
new file mode 100755
index 00000000..2ac082c1
--- /dev/null
+++ b/_git_hooks/update
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# git update hook to check that pushed changes don't introduce new flake8
+# errors
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+ echo "Don't run this script from the command line." >&2
+ echo " (if you want, you could supply GIT_DIR then run" >&2
+ echo " $0 [ )" >&2
+ exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+ echo "usage: $0 ][ " >&2
+ exit 1
+fi
+
+
+TMPDIR=`mktemp -d`
+TMPDIFF=`tempfile`
+
+[ $refname != "refs/heads/master" -a $refname != "refs/heads/stable" ] && exit 0
+
+git diff --unified=1 $oldrev $newrev -- '*.py' >${TMPDIFF}
+
+# there is no working tree in bare git repository, so we recreate it for flake8
+git archive $newrev | tar -x -C ${TMPDIR}
+
+cd ${TMPDIR}
+# report only errors on lines in diff
+# (if threre was flake8 installed on atrey, we could just call flake8)
+/akce/MaM/WWW/mamweb-test/bin/flake8 --diff <${TMPDIFF}
+status=$?
+if [ $status != 0 ] ; then
+ echo
+ echo -n "Změny, které se snažíte pushnout, obsahují kód v pythonu "
+ echo -n "nevyhovující flake8 (viz výše). Opravte je a zkuste to znovu. "
+ echo -n "Nezapomeňte, že můžete editovat historii (git commit --amend, "
+ echo -n "git rebase -i). Pokud byste chybu příště raději odhalili už při "
+ echo "commitu, zkopírujte si pre-commit hook z _git_hooks do .git/hooks."
+ echo
+fi
+
+rm -rf ${TMPDIR}
+rm -f ${TMPDIFF}
+
+exit $status
diff --git a/korektury/migrations/0010_Pridani_odkazu_na_organizatora.py b/korektury/migrations/0010_Pridani_odkazu_na_organizatora.py
new file mode 100644
index 00000000..e76d5058
--- /dev/null
+++ b/korektury/migrations/0010_Pridani_odkazu_na_organizatora.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0041_konfery'),
+ ('korektury', '0009_trizeni_korektur_v_seznamu'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='komentar',
+ name='autor_org',
+ field=models.ForeignKey(blank=True, to='seminar.Organizator', help_text='Autor koment\xe1\u0159e', null=True),
+ ),
+ migrations.AddField(
+ model_name='oprava',
+ name='autor_org',
+ field=models.ForeignKey(blank=True, to='seminar.Organizator', help_text=b'Autor opravy', null=True),
+ ),
+ ]
diff --git a/korektury/migrations/0011_prevod_autora_z_charField_na_Organizator.py b/korektury/migrations/0011_prevod_autora_z_charField_na_Organizator.py
new file mode 100644
index 00000000..dddb07be
--- /dev/null
+++ b/korektury/migrations/0011_prevod_autora_z_charField_na_Organizator.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+def transform_autor(apps, schema_editor):
+ print
+ Organizator = apps.get_model('seminar', 'Organizator')
+
+ # preorgovani oprav
+ Oprava = apps.get_model('korektury', 'Oprava')
+ for oprava in Oprava.objects.all():
+ jmeno = oprava.autor.split()
+ if len(jmeno) == 2:
+ try:
+ org = Organizator.objects.get(user__first_name=jmeno[0],
+ user__last_name=jmeno[1])
+ oprava.autor_org = org
+ oprava.save()
+ except:
+ print "Org nenalezen -- mažu korekturu"
+# oprava.delete()
+ else:
+ print "Org nenalezen -- mažu korekturu"
+ oprava.delete()
+
+ # preorgovani komentaru
+ Komentar = apps.get_model('korektury', 'Komentar')
+ for komentar in Komentar.objects.all():
+ jmeno = komentar.autor.split()
+ if len(jmeno) == 2:
+ try:
+ org = Organizator.objects.get(user__first_name=jmeno[0],
+ user__last_name=jmeno[1])
+ komentar.autor_org = org
+ komentar.save()
+ except:
+ print "Org nenalezen -- mažu korekturu"
+# oprava.delete()
+ else:
+ print "Org nenalezen -- mažu korekturu"
+ komentar.delete()
+
+def back(apps, schema_editor):
+ pass
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('korektury', '0010_Pridani_odkazu_na_organizatora'),
+ ]
+
+ operations = [
+ migrations.RunPython(transform_autor, back),
+ ]
diff --git a/korektury/migrations/0012_delete_autor.py b/korektury/migrations/0012_delete_autor.py
new file mode 100644
index 00000000..4f41a955
--- /dev/null
+++ b/korektury/migrations/0012_delete_autor.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('korektury', '0011_prevod_autora_z_charField_na_Organizator'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='komentar',
+ name='autor',
+ ),
+ migrations.RemoveField(
+ model_name='oprava',
+ name='autor',
+ ),
+ ]
diff --git a/korektury/migrations/0013_rename_autor_org.py b/korektury/migrations/0013_rename_autor_org.py
new file mode 100644
index 00000000..db0d3151
--- /dev/null
+++ b/korektury/migrations/0013_rename_autor_org.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('korektury', '0012_delete_autor'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='komentar',
+ old_name='autor_org',
+ new_name='autor',
+ ),
+ migrations.RenameField(
+ model_name='oprava',
+ old_name='autor_org',
+ new_name='autor',
+ ),
+ ]
diff --git a/korektury/models.py b/korektury/models.py
index 311d5e20..a07c6945 100644
--- a/korektury/models.py
+++ b/korektury/models.py
@@ -6,13 +6,22 @@ from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from django.utils.encoding import force_unicode
from django.core.exceptions import ObjectDoesNotExist
+from django.utils.text import get_valid_filename
+
+from seminar.models import Organizator
import subprocess
from reversion import revisions as reversion
-# PrilohaReseni method
+from unidecode import unidecode
+
+
def generate_filename(self, filename):
- clean = filename.replace('/','-').replace('\0', '').replace(":","_")
+ clean = get_valid_filename(
+ unidecode(
+ filename.replace('/', '-').replace('\0', '').replace(":", "_")
+ )
+ )
fname = "%s_%s" % (
timezone.now().strftime('%Y-%m-%d-%H_%M'),
clean)
@@ -64,23 +73,18 @@ class KorekturovanePDF(models.Model):
except ObjectDoesNotExist:
pass
super(KorekturovanePDF, self).save()
- print("\nSaving")
- print(self.pdf.path)
- print(self.pdf.url)
filename = os.path.split(self.pdf.file.name)[1].split(".")[0]
- try:
- os.listdir(settings.KOREKTURY_IMG_DIR)
- except OSError:
- os.mkdir(settings.KOREKTURY_IMG_DIR)
+ dirname = os.path.join(settings.MEDIA_ROOT, settings.KOREKTURY_IMG_DIR)
+ if not os.path.exists(dirname):
+ os.mkdir(dirname)
while True:
res = subprocess.call([
- "convert",
- "-density","180x180",
- "-geometry"," 1024x1448",
- self.pdf.path+"[%d]"%self.stran,
- os.path.join(settings.BASE_DIR, "media",
- settings.KOREKTURY_IMG_DIR,
- "%s-%d.png"%(filename,self.stran))])
+ "convert",
+ "-density", "180x180",
+ "-geometry", " 1024x1448",
+ "%s[%d]" % (self.pdf.path, self.stran),
+ os.path.join(dirname, "%s-%d.png" % (filename, self.stran))
+ ])
if res==1:
break
self.stran +=1
@@ -120,9 +124,9 @@ class Oprava(models.Model):
status = models.CharField(u'stav opravy',max_length=16, choices=STATUS_CHOICES, blank=False,
default = STATUS_K_OPRAVE)
-
- # TODO: Změnit na cizí klíč do orgů
- autor = models.CharField(u'autor opravy',blank = True,max_length=20, help_text='Autor opravy')
+ autor = models.ForeignKey(Organizator, blank = True,
+ help_text='Autor opravy',
+ null = True)
text = models.TextField(u'text opravy',blank = True, help_text='Text opravy')
@@ -150,8 +154,9 @@ class Komentar(models.Model):
cas = models.DateTimeField(u'čas komentáře',default=timezone.now,help_text = 'Čas zadání komentáře')
oprava = models.ForeignKey(Oprava)
- # TODO: Změnit na cizí klíč do orgů
- autor = models.CharField(u'autor komentáře',blank = True,max_length=20, help_text='Autor komentáře')
+ autor = models.ForeignKey(Organizator, blank = True,
+ help_text = u'Autor komentáře',
+ null = True)
text = models.TextField(u'text komentáře',blank = True, help_text='Text komentáře')
diff --git a/korektury/templates/korektury/opraf.html b/korektury/templates/korektury/opraf.html
index 83c997ab..04cfc2de 100644
--- a/korektury/templates/korektury/opraf.html
+++ b/korektury/templates/korektury/opraf.html
@@ -82,7 +82,10 @@
]
- Děkujeme opravovatelům: {% for autor,pocet in zasluhy.items %} {{autor}}({{pocet}}) {% endfor %}
+ Děkujeme opravovatelům:
+ {% for autor,pocet in zasluhy.items %}
+ {{autor}} ({{pocet}}){% if not forloop.last %},{% endif %}
+ {% endfor %}
{% for o in opravy %}
diff --git a/korektury/views.py b/korektury/views.py
index d6d126e4..931ab67c 100644
--- a/korektury/views.py
+++ b/korektury/views.py
@@ -3,8 +3,10 @@ from django.shortcuts import get_object_or_404, render
from django.views import generic
from django.utils.translation import ugettext as _
from django.conf import settings
+from django.http import HttpResponseForbidden
+from django.core.mail import send_mail
-from .models import Oprava,Komentar,KorekturovanePDF
+from .models import Oprava,Komentar,KorekturovanePDF, Organizator
from .forms import OpravaForm
import subprocess
@@ -29,14 +31,17 @@ class KorekturyView(generic.TemplateView):
form = self.form_class(request.POST)
q = request.POST
scroll = q.get('scroll')
- autor = q.get('au')
+ # prirazeni autora podle prihlaseni
+ autor_user = request.user
+ # pokud existuje ucet (user), ale neni to organizator = 403
+ autor = Organizator.objects.filter(user=autor_user).first()
if not autor:
- autor = 'anonym'
+ return HttpResponseForbidden()
+
if not scroll:
scroll = 0
-
action = q.get('action')
if (action == u''): # Přidej
x = int(q.get('x'))
@@ -79,6 +84,7 @@ class KorekturyView(generic.TemplateView):
text = q.get('txt')
kom = Komentar(oprava=op,autor=autor,text=text)
kom.save()
+ self.send_email_notification_komentar(op, autor, text)
elif (action == u'update-comment'):
id = int(q.get('id'))
kom = Komentar.objects.get(id=id)
@@ -112,6 +118,32 @@ class KorekturyView(generic.TemplateView):
context['autor'] = autor
return render(request, 'korektury/opraf.html',context)
+ def send_email_notification_komentar(self, oprava, autor, text):
+ ''' Rozesle e-mail pri pridani komentare,
+ ktery obsahuje text komentare.
+ '''
+
+ # parametry e-mailu
+ odkaz = "https://mam.mff.cuni.cz:1443/korektury/{}/".format(oprava.pdf.pk)
+ from_email = 'korekturovatko@mam.mff.cuni.cz'
+ subject = u'Nová korektura od {} v {}'.format(autor,
+ oprava.pdf.nazev)
+ text = u"Text komentáře:\n\n{}\n\n=== Konec textu komentáře ===\n\
+ \nodkaz do korekturovátka: {}\n\
+ \nVaše korekturovátko\n".format(text, odkaz)
+
+ # Prijemci e-mailu
+ emails = set()
+ email = oprava.autor.user.email
+ if email:
+ emails.add(email)
+ for komentar in oprava.komentar_set.all():
+ email = komentar.autor.user.email
+ if email:
+ emails.add(email)
+
+ send_mail(subject, text, from_email, list(emails))
+
def get_context_data(self, **kwargs):
context = super(KorekturyView,self).get_context_data(**kwargs)
pdf = get_object_or_404(KorekturovanePDF, id=self.kwargs['pdf'])
@@ -141,6 +173,7 @@ class KorekturyView(generic.TemplateView):
context['opravy'] = opravy
context['zasluhy'] = zasluhy
return context
+
def form_valid(self,form):
return super(KorekturyView,self).form_valid(form)
diff --git a/requirements.txt b/requirements.txt
index 77d913ea..1800d357 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,6 +8,8 @@ pytz==2015.7
six==1.10.0
pexpect==4.0.1
traitlets==4.0.0
+Unidecode==0.4.19
+flake8==3.0.4
# Django and modules
diff --git a/seminar/models.py b/seminar/models.py
index 15367d3a..4c8fc3f0 100644
--- a/seminar/models.py
+++ b/seminar/models.py
@@ -12,15 +12,10 @@ from django.utils.text import slugify
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
+from django.utils.text import get_valid_filename
from imagekit.models import ImageSpecField, ProcessedImageField
from imagekit.processors import ResizeToFit, Transpose
-from PIL import Image
-import os
-#from functools import partial
-from cStringIO import StringIO
-from django.core.files.base import ContentFile
-
from django_countries.fields import CountryField
from solo.models import SingletonModel
from taggit.managers import TaggableManager
@@ -29,6 +24,8 @@ from reversion import revisions as reversion
from seminar.utils import roman
+from unidecode import unidecode
+
class SeminarModelBase(models.Model):
@@ -557,28 +554,35 @@ class Reseni(SeminarModelBase):
super(Reseni, self).save(*args, **kwargs)
-# PrilohaReseni method
-# TODO vyresit partial, tak aby slo migrovat
-#def generate_filename(self, filename, directory):
-# Django 1.9 podporuje partial
-
-def generate_filename(self, filename):
- clean = filename.replace('/','-').replace('\0', '')
+def aux_generate_filename(self, filename):
+ """Pomocná funkce generující ošetřený název souboru v adresáři s datem"""
+ clean = get_valid_filename(
+ unidecode(filename.replace('/', '-').replace('\0', ''))
+ )
datedir = timezone.now().strftime('%Y-%m')
fname = "%s_%s" % (
timezone.now().strftime('%Y-%m-%d-%H:%M'),
clean)
- return os.path.join(settings.SEMINAR_RESENI_DIR, datedir, fname)
+ return os.path.join(datedir, fname)
+
+# Django neumí jednoduše serializovat partial nebo třídu s __call__
+# (https://docs.djangoproject.com/en/1.8/topics/migrations/),
+# neprojdou pak migrace. Takže rozlišení funkcí generujících názvy souboru
+# podle adresáře řešíme takto.
+
def generate_filename_konfera(self, filename):
- clean = filename.replace('/','-').replace('\0', '')
- datedir = timezone.now().strftime('%Y-%m')
- fname = "%s_%s" % (
- timezone.now().strftime('%Y-%m-%d-%H:%M'),
- clean)
- return os.path.join(settings.SEMINAR_KONFERY_DIR, datedir, fname)
-# TODO vyresit partial tak, aby slo migrovat
-# return os.path.join(directory, datedir, fname)
+ return os.path.join(
+ settings.SEMINAR_KONFERY_DIR,
+ aux_generate_filename(self, filename)
+ )
+
+
+def generate_filename(self, filename):
+ return os.path.join(
+ settings.SEMINAR_RESENI_DIR,
+ aux_generate_filename(self, filename)
+ )
@reversion.register(ignore_duplicate_revisions=True)