Browse Source

Merge branch 'master' into stable

remotes/origin/posli-mail-autorovi-korektury v1.8
Bc. Petr Pecha 8 years ago
parent
commit
661a940756
  1. 4
      Makefile
  2. 16
      _git_hooks/README.md
  3. 6
      _git_hooks/pre-commit
  4. 53
      _git_hooks/update
  5. 25
      korektury/migrations/0010_Pridani_odkazu_na_organizatora.py
  6. 56
      korektury/migrations/0011_prevod_autora_z_charField_na_Organizator.py
  7. 22
      korektury/migrations/0012_delete_autor.py
  8. 24
      korektury/migrations/0013_rename_autor_org.py
  9. 47
      korektury/models.py
  10. 5
      korektury/templates/korektury/opraf.html
  11. 41
      korektury/views.py
  12. 2
      requirements.txt
  13. 48
      seminar/models.py

4
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

16
_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

6
_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

53
_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 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&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

25
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),
),
]

56
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),
]

22
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',
),
]

24
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',
),
]

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

5
korektury/templates/korektury/opraf.html

@ -82,7 +82,10 @@
<!-- /Zmenit stav PDF !-->
<hr/>
<p>
Děkujeme opravovatelům: {% for autor,pocet in zasluhy.items %} {{autor}}({{pocet}}) {% endfor %}</p>
Děkujeme opravovatelům:
{% for autor,pocet in zasluhy.items %}
{{autor}} ({{pocet}}){% if not forloop.last %},{% endif %}
{% endfor %}</p>
<hr>
{% for o in opravy %}

41
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)

2
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

48
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)

Loading…
Cancel
Save