Merge remote-tracking branch 'origin/master' into stable
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						|  | @ -20,3 +20,6 @@ | |||
| 
 | ||||
| # secrets | ||||
| /django.secret | ||||
| 
 | ||||
| # vim tmp files | ||||
| *~ | ||||
|  |  | |||
							
								
								
									
										14
									
								
								korektury/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,14 @@ | |||
| - korektura potrebuje reakci | ||||
| + komentáře fixně na username | ||||
|   - používat skutečné jméno? | ||||
| - vyžádat pozornost autora obsahu | ||||
| - zvednout upload limit na 5MB | ||||
| - sbalit a rozbalit korekturu | ||||
| - nápověda | ||||
| - nahrávání jiných věcí než PDF - kontrolovat? | ||||
| - stylování | ||||
| - vylepšení hlavičky | ||||
|   - seznam PDF, homepage M&M, admin, wiki | ||||
| - seznam PDF - co zobrazovat? | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								korektury/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										16
									
								
								korektury/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,16 @@ | |||
| from django.contrib import admin | ||||
| from reversion.admin import VersionAdmin | ||||
| from korektury.models import KorekturovanePDF | ||||
| 
 | ||||
| # Register your models here. | ||||
| class KorekturovanePDFAdmin(VersionAdmin): | ||||
|      readonly_fields = ['cas', 'stran'] | ||||
|      fieldsets = [ | ||||
|          (None,              {'fields': ['pdf', 'cas', 'stran', 'nazev', 'komentar']}), | ||||
| #         (u'PDF',       {'fields': ['pdf']}), | ||||
|          ] | ||||
|      list_display = ['pdf', 'cas', 'stran'] | ||||
|      list_filter = [] | ||||
|      search_fields = [] | ||||
|   | ||||
| admin.site.register(KorekturovanePDF, KorekturovanePDFAdmin) | ||||
							
								
								
									
										13
									
								
								korektury/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,13 @@ | |||
| from django import forms | ||||
| 
 | ||||
| class OpravaForm(forms.Form): | ||||
|     text = forms.CharField(max_length=256) | ||||
|     autor = forms.CharField(max_length=20) | ||||
|     x = forms.IntegerField() | ||||
|     y = forms.IntegerField() | ||||
|     scroll = forms.CharField(max_length=256) | ||||
|     pdf = forms.CharField(max_length=256) | ||||
|     img_id = forms.CharField(max_length=256) | ||||
|     id = forms.CharField(max_length=256) | ||||
|     action = forms.CharField(max_length=256) | ||||
| 
 | ||||
							
								
								
									
										63
									
								
								korektury/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,63 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import korektury.models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='KorekturovanePDF', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('pdf', models.FileField(upload_to=korektury.models.generate_filename, verbose_name='pdf')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'db_table': 'korekturovane_cislo', | ||||
|                 'verbose_name': 'PDF k oprav\xe1m', | ||||
|                 'verbose_name_plural': 'PDF k oprav\xe1m', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='Oprava', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('strana', models.IntegerField(help_text=b'Strana s opravou (od 0)', verbose_name='strana s opravou')), | ||||
|                 ('x', models.IntegerField(verbose_name='x-ov\xe1 sou\u0159adnice bugu')), | ||||
|                 ('y', models.IntegerField(verbose_name='y-ov\xe1 sou\u0159adnice bugu')), | ||||
|                 ('status', models.CharField(default=b'k_oprave', max_length=16, verbose_name='stav opravy', choices=[(b'k_oprave', 'K oprav\u011b'), (b'opraveno', 'Opraveno'), (b'smazano', 'Smaz\xe1no')])), | ||||
|                 ('autor', models.TextField(help_text=b'Autor opravy', verbose_name='autor opravy', blank=True)), | ||||
|                 ('text', models.TextField(help_text=b'Text opravy', verbose_name='text opravy', blank=True)), | ||||
|             ], | ||||
|             options={ | ||||
|                 'ordering': ['y', 'x'], | ||||
|                 'db_table': 'opravy', | ||||
|                 'verbose_name': 'Oprava', | ||||
|                 'verbose_name_plural': 'Opravy', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='OpravaKomentar', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('cas', models.DateTimeField(help_text=b'\xc4\x8cas zad\xc3\xa1n\xc3\xad koment\xc3\xa1\xc5\x99e', verbose_name='\u010das koment\xe1\u0159e')), | ||||
|                 ('autor', models.TextField(help_text=b'Autor koment\xc3\xa1\xc5\x99e', verbose_name='autor koment\xe1\u0159e', blank=True)), | ||||
|                 ('text', models.TextField(help_text=b'Text koment\xc3\xa1\xc5\x99e', verbose_name='text koment\xe1\u0159e', blank=True)), | ||||
|                 ('oprava', models.ForeignKey(to='korektury.Oprava')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'ordering': ['cas'], | ||||
|                 'db_table': 'opravy_komentare', | ||||
|                 'verbose_name': 'Koment\xe1\u0159 k oprav\u011b', | ||||
|                 'verbose_name_plural': 'Koment\xe1\u0159e k oprav\u011b', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										39
									
								
								korektury/migrations/0002_auto_20151202_2351.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,39 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django.utils.timezone | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0001_initial'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='Komentar', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('cas', models.DateTimeField(default=django.utils.timezone.now, help_text=b'\xc4\x8cas zad\xc3\xa1n\xc3\xad koment\xc3\xa1\xc5\x99e', verbose_name='\u010das koment\xe1\u0159e')), | ||||
|                 ('autor', models.TextField(help_text=b'Autor koment\xc3\xa1\xc5\x99e', verbose_name='autor koment\xe1\u0159e', blank=True)), | ||||
|                 ('text', models.TextField(help_text=b'Text koment\xc3\xa1\xc5\x99e', verbose_name='text koment\xe1\u0159e', blank=True)), | ||||
|                 ('oprava', models.ForeignKey(to='korektury.Oprava')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'ordering': ['cas'], | ||||
|                 'db_table': 'komentare', | ||||
|                 'verbose_name': 'Koment\xe1\u0159 k oprav\u011b', | ||||
|                 'verbose_name_plural': 'Koment\xe1\u0159e k oprav\u011b', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|         migrations.RemoveField( | ||||
|             model_name='opravakomentar', | ||||
|             name='oprava', | ||||
|         ), | ||||
|         migrations.DeleteModel( | ||||
|             name='OpravaKomentar', | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										27
									
								
								korektury/migrations/0003_auto_20151204_1855.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,27 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django.utils.timezone | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0002_auto_20151202_2351'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='cas', | ||||
|             field=models.DateTimeField(default=django.utils.timezone.now, help_text=b'\xc4\x8cas vlo\xc5\xbeen\xc3\xad PDF', verbose_name='\u010das vlo\u017een\xed PDF'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='stran', | ||||
|             field=models.IntegerField(default=0, help_text=b'Po\xc4\x8det stran PDF', verbose_name='po\u010det stran'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										26
									
								
								korektury/migrations/0004_auto_20151204_2240.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,26 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0003_auto_20151204_1855'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='komentar', | ||||
|             field=models.TextField(help_text=b'Koment\xc3\xa1\xc5\x99 ke korekturovan\xc3\xa9mu PDF (nap\xc5\x99. na co se zam\xc4\x9b\xc5\x99it)', verbose_name='koment\xe1\u0159 k PDF', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='nazev', | ||||
|             field=models.TextField(help_text=b'N\xc3\xa1zev (nap\xc5\x99. 22.1 verze 4) korekturovan\xc3\xa9ho PDF', verbose_name='n\xe1zev PDF', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										32
									
								
								korektury/migrations/0005_auto_20151204_2244.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,32 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0004_auto_20151204_2240'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='komentar', | ||||
|             name='autor', | ||||
|             field=models.CharField(help_text=b'Autor koment\xc3\xa1\xc5\x99e', max_length=20, verbose_name='autor koment\xe1\u0159e', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='nazev', | ||||
|             field=models.CharField(help_text=b'N\xc3\xa1zev (nap\xc5\x99. 22.1 verze 4) korekturovan\xc3\xa9ho PDF', max_length=50, verbose_name='n\xe1zev PDF', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='oprava', | ||||
|             name='autor', | ||||
|             field=models.CharField(help_text=b'Autor opravy', max_length=20, verbose_name='autor opravy', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										20
									
								
								korektury/migrations/0006_oprava_pdf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,20 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0005_auto_20151204_2244'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='oprava', | ||||
|             name='pdf', | ||||
|             field=models.ForeignKey(default=-1, to='korektury.KorekturovanePDF'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										33
									
								
								korektury/migrations/0007_auto_20151225_1237.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,33 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import korektury.models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('korektury', '0006_oprava_pdf'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='status', | ||||
|             field=models.CharField(default=b'pridavani', max_length=16, verbose_name='stav PDF', choices=[(b'pridavani', 'P\u0159id\xe1v\xe1n\xed korektur'), (b'zanaseni', 'Korektury jsou zan\xe1\u0161eny'), (b'zastarale', 'Star\xe1 verze, nekorigovat')]), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='korekturovanepdf', | ||||
|             name='pdf', | ||||
|             field=models.FileField(upload_to=korektury.models.generate_filename, verbose_name='PDF'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='oprava', | ||||
|             name='status', | ||||
|             field=models.CharField(default=b'k_oprave', max_length=16, verbose_name='stav opravy', choices=[(b'k_oprave', 'K oprav\u011b'), (b'opraveno', 'Opraveno'), (b'neni_chyba', 'Nen\xed chyba'), (b'k_reakci', 'K reakci autora textu'), (b'smazano', 'Smaz\xe1no')]), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										0
									
								
								korektury/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										176
									
								
								korektury/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,176 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import os | ||||
| import random | ||||
| from django.db import models | ||||
| from django.contrib import auth | ||||
| from django.utils import timezone | ||||
| from django.conf import settings | ||||
| from django.utils.encoding import python_2_unicode_compatible | ||||
| from django.utils.encoding import force_unicode | ||||
| 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 imagekit.models import ImageSpecField, ProcessedImageField | ||||
| from imagekit.processors import ResizeToFit, Transpose | ||||
| 
 | ||||
| import os | ||||
| import subprocess | ||||
| 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 | ||||
| 
 | ||||
| import reversion | ||||
| 
 | ||||
| # PrilohaReseni method | ||||
| def generate_filename(self, filename): | ||||
|     clean = filename.replace('/','-').replace('\0', '').replace(":","_") | ||||
|     fname = "%s_%s" % ( | ||||
|         timezone.now().strftime('%Y-%m-%d-%H_%M'), | ||||
|         clean) | ||||
|     return os.path.join(settings.KOREKTURY_PDF_DIR, fname) | ||||
| 
 | ||||
| 
 | ||||
| #@reversion.register(ignore_duplicate_revision=True) | ||||
| #@python_2_unicode_compatible | ||||
| class KorekturovanePDF(models.Model): | ||||
|     class Meta: | ||||
|         db_table = 'korekturovane_cislo' | ||||
|         verbose_name = u'PDF k opravám' | ||||
|         verbose_name_plural = u'PDF k opravám' | ||||
|      | ||||
|     #Interní ID | ||||
|     id  = models.AutoField(primary_key = True) | ||||
| 
 | ||||
|     cas = models.DateTimeField(u'čas vložení PDF',default=timezone.now,help_text = 'Čas vložení PDF') | ||||
| 
 | ||||
|     nazev = models.CharField(u'název PDF',blank = True,max_length=50, help_text='Název (např. 22.1 verze 4) korekturovaného PDF') | ||||
| 
 | ||||
|     komentar = models.TextField(u'komentář k PDF',blank = True, help_text='Komentář ke korekturovanému PDF (např. na co se zaměřit)') | ||||
| 
 | ||||
|     pdf = models.FileField(u'PDF', upload_to = generate_filename) | ||||
| 
 | ||||
|     stran = models.IntegerField(u'počet stran', help_text = 'Počet stran PDF', default = 0) | ||||
|     STATUS_PRIDAVANI = 'pridavani' | ||||
|     STATUS_ZANASENI = 'zanaseni' | ||||
|     STATUS_ZASTARALE = 'zastarale' | ||||
|     STATUS_CHOICES = ( | ||||
|             (STATUS_PRIDAVANI, u'Přidávání korektur'), | ||||
|             (STATUS_ZANASENI, u'Korektury jsou zanášeny'), | ||||
|             (STATUS_ZASTARALE, u'Stará verze, nekorigovat'), | ||||
|             ) | ||||
|     status = models.CharField(u'stav PDF',max_length=16, choices=STATUS_CHOICES, blank=False, | ||||
|             default = STATUS_PRIDAVANI) | ||||
|   | ||||
|    | ||||
|     #TODO Nepovinný foreign key k číslu | ||||
| 
 | ||||
|     def save(self): | ||||
|         # Pokud se nezmenilo PDF, tak nepregenerovavej nahledy | ||||
|         try: | ||||
|             original = KorekturovanePDF.objects.get(pk=self.pk) | ||||
|             if original.pdf == self.pdf: | ||||
|                 super(KorekturovanePDF, self).save() | ||||
|                 return | ||||
|         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) | ||||
|         while True: | ||||
|             res = subprocess.call([ | ||||
|             "convert", | ||||
|             "-density","180x180", | ||||
|             "-geometry"," 1024x1448", | ||||
|             self.pdf.path+"[%d]"%self.stran, | ||||
|             os.path.join(settings.KOREKTURY_IMG_DIR, "%s-%d.png"%(filename,self.stran))]) | ||||
|             if res==1: | ||||
|                 break | ||||
|             self.stran +=1 | ||||
|         super(KorekturovanePDF, self).save() | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revision=True) | ||||
| @python_2_unicode_compatible | ||||
| class Oprava(models.Model): | ||||
|     class Meta: | ||||
|         db_table = 'opravy' | ||||
|         verbose_name = u'Oprava' | ||||
|         verbose_name_plural = u'Opravy' | ||||
|         ordering = ['y','x'] | ||||
|      | ||||
|     #Interní ID | ||||
|     id  = models.AutoField(primary_key = True) | ||||
| 
 | ||||
|     pdf = models.ForeignKey(KorekturovanePDF, default=-1) | ||||
| 
 | ||||
|     strana = models.IntegerField(u'strana s opravou', help_text='Strana s opravou (od 0)') | ||||
| 
 | ||||
|     x = models.IntegerField(u'x-ová souřadnice bugu') | ||||
|     y = models.IntegerField(u'y-ová souřadnice bugu') | ||||
| 
 | ||||
|     STATUS_K_OPRAVE = 'k_oprave' | ||||
|     STATUS_OPRAVENO = 'opraveno' | ||||
|     STATUS_NENI_CHYBA = 'neni_chyba' | ||||
|     STATUS_K_REAKCI = 'k_reakci' | ||||
|     STATUS_SMAZANO = 'smazano' | ||||
|     STATUS_CHOICES = ( | ||||
|             (STATUS_K_OPRAVE, u'K opravě'), | ||||
|             (STATUS_OPRAVENO, u'Opraveno'), | ||||
|             (STATUS_NENI_CHYBA, u'Není chyba'), | ||||
|             (STATUS_K_REAKCI, u'K reakci autora textu'), | ||||
|             (STATUS_SMAZANO, u'Smazáno'), | ||||
|             ) | ||||
|     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') | ||||
|      | ||||
|     text = models.TextField(u'text opravy',blank = True, help_text='Text opravy') | ||||
| 
 | ||||
| #    def __init__(self,dictionary): | ||||
| #        for k,v in dictionary.items(): | ||||
| #            setattr(self,k,v) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u'%s od %s: %s'%(self.status,self.autor,self.text)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revision=True) | ||||
| @python_2_unicode_compatible | ||||
| class Komentar(models.Model): | ||||
|     class Meta: | ||||
|         db_table = 'komentare' | ||||
|         verbose_name = u'Komentář k opravě' | ||||
|         verbose_name_plural = u'Komentáře k opravě' | ||||
|         ordering = ['cas'] | ||||
|      | ||||
|     #Interní ID | ||||
|     id  = models.AutoField(primary_key = True) | ||||
| 
 | ||||
|     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') | ||||
|      | ||||
|     text = models.TextField(u'text komentáře',blank = True, help_text='Text komentáře') | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u'%s od %s: %s'%(self.cas,self.autor,self.text)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/check.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 697 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/comment.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 726 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/cross.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 717 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/delete-gr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 347 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/delete.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 500 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/edit-gr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 973 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/edit.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/link.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/next-gr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 881 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/next.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 557 B | 
							
								
								
									
										
											BIN
										
									
								
								korektury/static/korektury/imgs/undo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 617 B | 
							
								
								
									
										145
									
								
								korektury/static/korektury/opraf.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,145 @@ | |||
| body{background: #f3f3f3; color: black;} | ||||
| body.comitting { | ||||
|     background: yellow; | ||||
| } | ||||
| body.deprecated { | ||||
|     background: red; | ||||
| } | ||||
| 
 | ||||
| img{background:white;} | ||||
| 
 | ||||
| .pointer-hi,  | ||||
| .pointer,  | ||||
| .pointer-wontfix,  | ||||
| .pointer-wontfix-hi,  | ||||
| .pointer-done,  | ||||
| .pointer-done-hi { | ||||
| 	position:absolute; | ||||
| 	/*border-bottom-left-radius: 10px; */ | ||||
| 	border-left: 2px solid yellow; | ||||
| 	border-bottom: 2px solid yellow; | ||||
| } | ||||
| 
 | ||||
| .pointer-done-hi,  | ||||
| .pointer-wontfix-hi,  | ||||
| .pointer-hi { | ||||
| 	border-width: 3px; | ||||
| } | ||||
| 
 | ||||
| .pointer {  | ||||
| 	border-color: #F00; /*IE*/ | ||||
| 	border-color: rgba(255, 0, 0, 0.35); | ||||
| } | ||||
| .pointer-hi { | ||||
| 	border-color: #F00; /*IE*/ | ||||
| 	border-color: rgba(255, 0, 0, 1); | ||||
| } | ||||
| .pointer-done { | ||||
| 	border-color: #00F; /*IE*/ | ||||
| 	border-color: rgba(0, 0, 255, 0.2); | ||||
| } | ||||
| .pointer-done-hi { | ||||
| 	border-color: #00F; /*IE*/ | ||||
| 	border-color: rgba(0, 0, 255, 1); | ||||
| } | ||||
| .pointer-wontfix { | ||||
| 	border-color: #00F; /*IE*/ | ||||
| 	border-color: rgba(128, 128, 128, 0.2); | ||||
| } | ||||
| .pointer-wontfix-hi { | ||||
| 	border-color: #00F; /*IE*/ | ||||
| 	border-color: rgba(128, 128, 128, 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .box:hover, | ||||
| .box-done:hover, | ||||
| .box-wontfix:hover{ | ||||
| 	border-width:3px; | ||||
| 	margin: 0px; | ||||
| } | ||||
| .box, .box-done, .box-wontfix { | ||||
| 	margin: 1px; | ||||
| 	background-color: white; | ||||
| 	width:300px; | ||||
| 	/*position:absolute;*/ | ||||
| 	padding: 3px; | ||||
| 	border: 2px solid black; | ||||
| 	border-radius: 10px; | ||||
| } | ||||
| .box { | ||||
| 	border-color: red; | ||||
| } | ||||
| .box-done { | ||||
| 	border-color: blue; | ||||
| } | ||||
| .box-wontfix { | ||||
| 	border-color: grey; | ||||
| } | ||||
| form { | ||||
| 	display:inline; | ||||
| } | ||||
| 
 | ||||
| .float-right{ | ||||
| 	float:right; | ||||
| } | ||||
| 
 | ||||
| .imgdiv { | ||||
| 	position:relative; | ||||
| 	left:0px; | ||||
| 	top:0px; | ||||
| } | ||||
| #commform-div { | ||||
| 	display: none; | ||||
| 	position: absolute; | ||||
| 	background-color: white; | ||||
| 	border: 1px solid; | ||||
| 	padding: 3px; | ||||
| 	/* | ||||
| 	width: 310; | ||||
| 	height: 220; | ||||
| 	*/ | ||||
| 	z-index: 10; | ||||
| 	border: 4px solid red; | ||||
| 	border-radius: 10px; | ||||
| 	background-color: white; | ||||
| } | ||||
| .close-button{ | ||||
| 	background-color: yellow;	 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .box button, | ||||
| .box img, | ||||
| .box-done button, | ||||
| .box-done img, | ||||
| .box-wontfix button, | ||||
| .box-wontfix img{ | ||||
| 	border: 1px solid white; | ||||
| 	background-color:transparent; | ||||
| 	margin:0; | ||||
| 	padding: 1px; | ||||
| } | ||||
| .box button:hover, | ||||
| .box img:hover, | ||||
| .box-done img:hover, | ||||
| .box-done button:hover, | ||||
| .box-wontfix img:hover, | ||||
| .box-wontfix button:hover{ | ||||
| 	border: 1px solid black; | ||||
| } | ||||
| 
 | ||||
| .comment hr { | ||||
| 	height: 0px; | ||||
| } | ||||
| 
 | ||||
| .corr-header { | ||||
|     overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .author { | ||||
|     font-weight: bold; | ||||
|     float: left; | ||||
|     margin-top: 3px; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										256
									
								
								korektury/static/korektury/opraf.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,256 @@ | |||
| function place_comments_one_div(img_id, comments) | ||||
| { | ||||
| 	var img = document.getElementById(img_id); | ||||
| 	if( img == null ) {  | ||||
| 		return; | ||||
| 	} | ||||
| 	var par = img.parentNode; | ||||
| 	var w = img.clientWidth; | ||||
| 	var h = img.clientHeight; | ||||
| 	var w_skip = 10; | ||||
| 	var h_skip = 5; | ||||
| 	var pointer_min_h = 30; | ||||
| 
 | ||||
| 	var bott_max = 0; | ||||
| 	var comments_sorted = comments.sort(function (a,b) { | ||||
| 		return a[2] - b[2]; | ||||
| 		//pokus o hezci kladeni poiteru, ale nic moc
 | ||||
| 		if( a[3] < b[3] ) {  | ||||
| 			return (a[2] + pointer_min_h)- b[2]; | ||||
| 		} else { | ||||
| 			return (a[2] - pointer_min_h)- b[2]; | ||||
| 		} | ||||
| 
 | ||||
| 	}); | ||||
| 	//console.log("w:" + w);
 | ||||
| 	for (c in comments_sorted) { | ||||
| 		var id = comments_sorted[c][0]; | ||||
| 		var x  = comments_sorted[c][1]; | ||||
| 		var y  = comments_sorted[c][2]; | ||||
| 
 | ||||
| 		var el = document.getElementById(id); | ||||
| 		var elp = document.getElementById(id + "-pointer"); | ||||
| 
 | ||||
| 		if( el == null  || elp == null ) {  | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		par.appendChild(elp); | ||||
| 		par.appendChild(el); | ||||
| 
 | ||||
| 		var delta_y = (y > bott_max) ?  0: bott_max - y + h_skip; | ||||
| 
 | ||||
| 		elp.style.left = x; | ||||
| 		elp.style.top = y ; | ||||
| 		elp.style.width = w - x  + w_skip; | ||||
| 		elp.style.height = pointer_min_h + delta_y; | ||||
| 		elp.img_id = img_id; | ||||
| 		el.img_id = img_id; | ||||
| 
 | ||||
| 		el.style.position = 'absolute'; | ||||
| 		el.style.left = w + w_skip; | ||||
| 		el.style.top = y + delta_y; | ||||
| 
 | ||||
| 		var bott =  el.offsetTop + el.offsetHeight; | ||||
| 		bott_max = ( bott_max > bott ) ?  bott_max : bott; | ||||
| 
 | ||||
| 		//console.log( "par.w:"  + par.style.width);
 | ||||
| 
 | ||||
| 	} | ||||
| 	if( par.offsetHeight < bott_max ) { | ||||
| 		//par.style.height = bott_max;
 | ||||
| 		//alert("preteklo to:"+ par.offsetHeight +",mx:" + bott_max );
 | ||||
| 		par.style.height = bott_max; | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ctrl-enter submits form
 | ||||
| function textarea_onkey(ev) | ||||
| { | ||||
| 	//console.log("ev:" + ev.keyCode + "," + ev.ctrlKey);
 | ||||
| 	if( (ev.keyCode  == 13 || ev.keyCode == 10 )  && ev.ctrlKey ) { | ||||
| 		var form = document.getElementById('commform'); | ||||
| 		if( form ) {  | ||||
| 			save_scroll(form); | ||||
| 			//form.action ='';
 | ||||
| 			form.submit(); | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| //hide comment  form
 | ||||
| function close_commform() { | ||||
| 	var formdiv = document.getElementById('commform-div'); | ||||
| 	if( formdiv == null ) { | ||||
| 		alert("form null"); | ||||
| 		return true; | ||||
| 	} | ||||
| 	formdiv.style.display = 'none'; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| // show comment form, when clicked to image
 | ||||
| function img_click(element, ev) { | ||||
| 	var body_class = document.body.className; | ||||
| 	switch(body_class){ | ||||
| 		case "comitting": | ||||
| 			if (!confirm("Právě jsou zanášeny korektury, opravdu chcete přidat novou?")) | ||||
| 				return; | ||||
| 			break; | ||||
| 		case "deprecated": | ||||
| 			if (!confirm("Toto PDF je již zastaralé, opravdu chcete vytvořit korekturu?")) | ||||
| 				return; | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	var dx, dy; | ||||
| 	var par = element.parentNode; | ||||
| 	if( ev.pageX != null ) {  | ||||
| 		dx = ev.pageX - par.offsetLeft; | ||||
| 		dy = ev.pageY - par.offsetTop; | ||||
| 	} else { //IE
 | ||||
| 		dx = ev.offsetX; | ||||
| 		dy = ev.offsetY; | ||||
| 	} | ||||
| 	var img_id = element.id; | ||||
| 	if( element.img_id != null ) { | ||||
| 		// click was to '-pointer'
 | ||||
| 		img_id = element.img_id; | ||||
| 	} | ||||
| 	return show_form(img_id, dx, dy, '', '', '', ''); | ||||
| } | ||||
| 
 | ||||
| // show comment form, when 'edit' or 'comment' button pressed
 | ||||
| function box_edit(button, action) | ||||
| { | ||||
| 	var divbox = button.parentNode.parentNode.parentNode; | ||||
| 	var id = divbox.id; | ||||
| 	var divpointer = document.getElementById(divbox.id + '-pointer'); | ||||
| 
 | ||||
| 	var text; | ||||
| 	if (action == 'update') { | ||||
| 		var text_el = document.getElementById(divbox.id + '-text'); | ||||
| 		text = text_el.innerHTML.unescapeHTML(); | ||||
| 
 | ||||
| 	} else { | ||||
| 		text = ''; | ||||
| 	} | ||||
| 
 | ||||
| 	var dx = parseInt(divpointer.style.left); | ||||
| 	var dy = parseInt(divpointer.style.top); | ||||
| 	//alert('not yet 2:' + text + text_el); // + divpointer.style.top "x" + divpo );
 | ||||
| 	id = id.substring(2); | ||||
| 	return show_form(divbox.img_id, dx, dy, id, text, action); | ||||
| } | ||||
| 
 | ||||
| // show comment form when 'update-comment' button pressed
 | ||||
| function update_comment(button) | ||||
| { | ||||
| 	var divbox = button.parentNode.parentNode.parentNode.parentNode; | ||||
| 	var id = divbox.id; | ||||
| 	var divpointer = document.getElementById(divbox.id + '-pointer'); | ||||
| 	var dx = parseInt(divpointer.style.left); | ||||
| 	var dy = parseInt(divpointer.style.top); | ||||
| 
 | ||||
| 	var commentdiv = button.parentNode.parentNode.parentNode; | ||||
| 	var id = commentdiv.id.substring(1); | ||||
| 	var text = document.getElementById('kt' + id).innerHTML.unescapeHTML(); | ||||
| 
 | ||||
| 	return show_form(divbox.img_id, dx, dy, id, text, 'update-comment'); | ||||
| } | ||||
| 
 | ||||
| //fill up comment form and show him
 | ||||
| function show_form(img_id, dx, dy, id, text, action) { | ||||
| 	var form = document.getElementById('commform'); | ||||
| 	var formdiv = document.getElementById('commform-div'); | ||||
| 	var textarea = document.getElementById('commform-text'); | ||||
| 	var inputX  = document.getElementById('commform-x'); | ||||
| 	var inputY  = document.getElementById('commform-y'); | ||||
| 	var inputImgId  = document.getElementById('commform-img-id'); | ||||
| 	var inputId  = document.getElementById('commform-id'); | ||||
| 	var inputAction  = document.getElementById('commform-action'); | ||||
| 	var img = document.getElementById(img_id); | ||||
| 
 | ||||
| 	if( formdiv == null || textarea == null ) { | ||||
| 		alert("form null"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	//form.action = "#" +  img_id;
 | ||||
| 
 | ||||
| 	// set hidden values
 | ||||
| 	inputX.value = dx; | ||||
| 	inputY.value = dy; | ||||
| 	inputImgId.value = img_id; | ||||
| 	inputId.value = id; | ||||
| 	inputAction.value = action; | ||||
| 	textarea.value = text; | ||||
| 
 | ||||
| 	//textarea.value = "dxy:"+ dx + "x" + dy + "\n" + 'id:' + img_id;
 | ||||
| 
 | ||||
| 	// show form
 | ||||
| 	formdiv.style.display = 'block'; | ||||
| 	formdiv.style.left = dx; | ||||
| 	formdiv.style.top = dy; | ||||
| 	 | ||||
| 	img.parentNode.appendChild(formdiv); | ||||
| 
 | ||||
| 	textarea.focus(); | ||||
| 
 | ||||
| 	return true; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| function box_onmouseover(box, stat) | ||||
| { | ||||
| 	var id = box.id; | ||||
| 	var pointer = document.getElementById(box.id + '-pointer'); | ||||
| 	switch (stat){ | ||||
| 		case 'done': | ||||
| 			pointer.className = 'pointer-done-hi'; | ||||
| 			break; | ||||
| 		case 'wontfix': | ||||
| 			pointer.className = 'pointer-wontfix-hi'; | ||||
| 			break; | ||||
| 		default: | ||||
| 			pointer.className = 'pointer-hi'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function box_onmouseout(box, stat) | ||||
| { | ||||
| 	var id = box.id; | ||||
| 	var pointer = document.getElementById(box.id + '-pointer'); | ||||
| 	switch (stat){ | ||||
| 		case 'done': | ||||
| 			pointer.className = 'pointer-done'; | ||||
| 			break; | ||||
| 		case 'wontfix': | ||||
| 			pointer.className = 'pointer-wontfix'; | ||||
| 			break; | ||||
| 		default: | ||||
| 			pointer.className = 'pointer'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function save_scroll(form) | ||||
| { | ||||
| 	//alert('save_scroll:' + document.body.scrollTop);
 | ||||
| 	form.scroll.value =  document.body.scrollTop; | ||||
| 	//alert('save_scroll:' + form.scroll.value);
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| String.prototype.unescapeHTML = function () {                                        | ||||
|         return(                                                                  | ||||
|             this.replace(/&/g,'&').                                          | ||||
|                 replace(/>/g,'>').                                            | ||||
|                 replace(/</g,'<').                                            | ||||
|                 replace(/"/g,'"')                                          | ||||
|         );                                                                      | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										1
									
								
								korektury/static/korektury/png/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | |||
| * | ||||
							
								
								
									
										1
									
								
								korektury/static/korektury/tmp/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | |||
| * | ||||
							
								
								
									
										9
									
								
								korektury/templates/korektury/base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,9 @@ | |||
| {% extends "base.html" %} | ||||
| 
 | ||||
| {% block content %} | ||||
| {# blok do kterého se nacita text, v pripade jinyhc templatu obalit vlastnim blokem #} | ||||
| {% endblock %} | ||||
| 
 | ||||
| {% block title %} | ||||
| {# blok pro titulek stranky #} | ||||
| {% endblock %} | ||||
							
								
								
									
										47
									
								
								korektury/templates/korektury/help.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,47 @@ | |||
| {% extends "korektury/base.html" %} | ||||
| {% load staticfiles %} | ||||
| 
 | ||||
| {% block title %} Nápověda ke korigovátku {% endblock title %} | ||||
| 
 | ||||
| {% block content %} | ||||
| <h1> Nápověda ke korigovátku</h1> | ||||
| <p> Korigovátko slouží ke korigování PDF souborů. Umožňuje přidávat a komentovat | ||||
| korektury a označovat je jako zanesené / irelevantní. Rovněž umožňuje o PDF | ||||
| říci, že jsou právě zanášeny korektury nebo že je zastaralé. | ||||
| <h2> Použití </h2> | ||||
| <p> | ||||
| Kliknu do PDF tam, kam chci zadat korekturu, napíši text a kliknu na Oprav! | ||||
| (nebo Ctrl-Enter). | ||||
| Korektura se zobrazí na pravé straně červeně. Korektura nelze smazat ani | ||||
| upravit. | ||||
| </p><p> | ||||
| Pokud chci korekturu okomentovat, kliknu na ikonu <img src="{% static "korektury/imgs/comment.png" %}"/>, | ||||
| napíši komentář a kliknu na Oprav! (nebo Ctrl-Enter). Komentář se zobrazí pod | ||||
| původní korekturou. | ||||
| </p> | ||||
| <h2> Tlačítka u korektury </h2> | ||||
| <ul> | ||||
|   <li> <img src="{% static "korektury/imgs/delete.png" %}"/> - smazat korekturu | ||||
|   <li> <img src="{% static "korektury/imgs/check.png" %}"/> - označt koreturu jako zanesenou | ||||
|   <li> <img src="{% static "korektury/imgs/cross.png" %}"/> - označit korekturu jako irelevantní | ||||
| 	(není to chyba, nebude zaneseno) | ||||
|   <li> <img src="{% static "korektury/imgs/edit.png" %}"/> - upravit text korektury | ||||
|   <li> <img src="{% static "korektury/imgs/comment.png" %}"/> - okomentovat korekturu | ||||
| </ul> | ||||
| <h2> Stavy </h2> | ||||
| <h3> Korektura </h3> | ||||
| <ul> | ||||
| 	<li> K opravě - zadaná, čeká na zanesení / zahození | ||||
| 	<li> Zanesená - zanesená v TeXu | ||||
| 	<li> Irelevantní - není to chyba, nebude zanesena | ||||
| 	<li> K reakci - vyžaduje reakci od autora <i>(zatím není | ||||
| 	implementováno)</i> | ||||
| </ul> | ||||
| <h3> PDF </h3> | ||||
| <ul> | ||||
| 	<li> Přidávání - probíhá přidávání korektur | ||||
| 	<li> Zanášení - probíhá zanášení korektur do TeXu | ||||
| 	<li> Zastaralé - PDF je zastaralé, nepřidávat nové korektury | ||||
| </ul> | ||||
| 
 | ||||
| {% endblock content %} | ||||
							
								
								
									
										187
									
								
								korektury/templates/korektury/opraf.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,187 @@ | |||
| {% load staticfiles %} | ||||
| 
 | ||||
| <html> | ||||
| <head> | ||||
| 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | ||||
|   <link rel="stylesheet" type="text/css" media="screen, projection" href="{% static "korektury/opraf.css"%}" /> | ||||
|   <script src="{% static "korektury/opraf.js"%}"></script> | ||||
| 	<title>Korektury {{pdf.nazev}}</title> | ||||
| </head> | ||||
| <body {% if pdf.status = 'zanaseni'%} class="comitting" {% elif pdf.status = 'zastarale' %} class="deprecated" {% endif %}>  | ||||
| 	<h1>Korektury {{pdf.nazev}}</h1> | ||||
| 	{% if pdf.status = 'zanaseni' %} <h2> Probíhá zanášení korektur, zvažte, zda chcete přidávat nové </h2> {% endif %} | ||||
| 	{% if pdf.status = 'zastarale' %} <h2> Toto PDF je již zastaralé, nepřidávejte nové korektury </h2> {% endif %} | ||||
| 	<i>{{pdf.komentar}}</i> | ||||
| 	<br> | ||||
| 	<i>Klikni na chybu, napiš komentář</i>  | | ||||
| 	<a href="../">seznam souborů</a> | | ||||
| 	<a href="../help">nápověda</a> |          | | ||||
| 	<a href="/">hlavní stránka</a> | | ||||
| 	<a href="https://mam.mff.cuni.cz/wiki">wiki</a> | | ||||
| 	<hr/> | ||||
| 
 | ||||
| 	<div id="commform-div"> | ||||
| 		<!-- Pridat korekturu / komentar !--> | ||||
| 		<form action='' onsubmit='save_scroll(this)' id="commform" method="POST"> | ||||
| 			{% csrf_token %} | ||||
| 			<input size="8" name="au" value="{{user.username}}"/> | ||||
| 			<input type=submit value="Oprav!"/> | ||||
| 			<button type="button" onclick="close_commform()">Zavřít</button> | ||||
| 	  		<br/> | ||||
| 	  		<textarea onkeypress="textarea_onkey(event);" id="commform-text" cols=40 rows=10 name="txt"></textarea> | ||||
| 	  		<br/> | ||||
| 	  		<input type="hidden" size="3" name="pdf" value='{{pdf.id}}'/> | ||||
| 	  		<input type="hidden" size="3" id="commform-x" name="x"/> | ||||
| 	  		<input type="hidden" size="3" id="commform-y" name="y"/> | ||||
| 	  		<input type="hidden" size="3" id="commform-img-id" name="img-id"/> | ||||
| 	  		<input type="hidden" size="3" id="commform-id" name="id"/> | ||||
| 	  		<input type="hidden" size="3" id="commform-action" name="action"/> | ||||
| 	  		<input type="hidden" size="3" id="commform-action" name="scroll"/> | ||||
| 		</form> | ||||
| 		<!-- /Pridat korekturu / komentar !--> | ||||
| 	</div> | ||||
| 
 | ||||
| 	{% for i in img_indexes %} | ||||
| 	<div class='imgdiv'> | ||||
| 		<img width='1021' height='1448'  | ||||
| 			onclick='img_click(this,event)' id='img-{{i}}'  | ||||
| 			src='/media/korektury/img/{{img_name}}-{{i}}.png'/> | ||||
| 	</div> | ||||
| 	<hr/> | ||||
| 	{% endfor %} | ||||
| 
 | ||||
| 	<!-- Smazat vsechny komentare !--> | ||||
| 	<form method="post"> | ||||
| 		{% csrf_token %} | ||||
| 		<input type='hidden' name='action' value='delall'/> | ||||
| 		<input type='submit' value='Smazat všechny komentáře'/> | ||||
| 		<input type='hidden' name='pdf' value='{{pdf.id}}'/> | ||||
| 		<input type='checkbox' name='yes'/> Souhlasím se smazáním všech kometářů | ||||
| 	</form> | ||||
| 	<!-- /Smazat vsechny komentare !--> | ||||
| 	<hr/> | ||||
| 	<h4>Změnit stav PDF:</h4> | ||||
| 	<i>Aktuální: {{pdf.status}}</i> | ||||
| 	<br> | ||||
| 	<!-- Zmenit stav PDF !--> | ||||
| 	<form method="post"> | ||||
| 		{% csrf_token %} | ||||
| 		<input type='hidden' name='action' value='set-state'/> | ||||
| 		<input type='hidden' name='pdf' value='{{pdf.id}}'/> | ||||
| 		<input type="radio" name="state" value="adding" {% if pdf.status = 'pridavani' %} checked {% endif %}>Přidávání korektur | ||||
| 		<br> | ||||
| 		<input type="radio" name="state" value="comitting" {% if pdf.status = 'zanaseni' %} checked {% endif %}>Zanášení korektur | ||||
| 		<br> | ||||
| 		<input type="radio" name="state" value="deprecated" {%	if pdf.status = 'zastarale' %} checked {% endif %}>Zastaralé, nekorigovat | ||||
| 		<br> | ||||
| 		<input type='submit' value='Změnit stav PDF'/> | ||||
| 	</form> | ||||
| 	 | ||||
| 	<!-- /Zmenit stav PDF !--> | ||||
| 	<hr/> | ||||
| 	<p> | ||||
| 	Děkujeme opravovatelům: {% for autor,pocet in zasluhy.items %} {{autor}}({{pocet}}) {% endfor %}</p> | ||||
| 	<hr> | ||||
| 
 | ||||
| 	{% for o in opravy %} | ||||
| 	<div onclick='img_click(this,event)' | ||||
| 		id='op{{o.id}}-pointer' | ||||
| 		class='pointer{%if o.status = 'opraveno' %}-done{% elif o.status = 'neni_chyba' %}-wontfix{% endif %}'> | ||||
| 	</div> | ||||
| 	<div name='op{{o.id}}' id='op{{o.id}}'  | ||||
| 	    class='box{%if o.status = 'opraveno' %}-done{% elif o.status = 'neni_chyba' %}-wontfix{% endif %}'  | ||||
| 	    onmouseover='box_onmouseover(this,{% if o.status = 'opraveno' %}"done"{% elif o.status = 'neni_chyba' %}"wontfix"{%else%}""{% endif %})'  | ||||
| 	    onmouseout='box_onmouseout(this,{% if o.status = 'opraveno' %}"done"{% elif o.status = 'neni_chyba' %}"wontfix"{%else%}""{% endif %})'>  | ||||
| 
 | ||||
|     	<div class='corr-header'>  | ||||
| 			<div class='author' id='op{{o.id}}-autor'>{{o.autor}}</div> | ||||
| 			<div class='float-right'> | ||||
| 				<!-- Existujici korektura !--> | ||||
| 	  			<form  action='' onsubmit='save_scroll(this)' method='POST'> | ||||
| 	   				{% csrf_token %} | ||||
| 	   				<input type='hidden' name="au" value="{{o.autor}}"/> | ||||
| 	   				<input type='hidden' name='pdf' value='{{pdf.id}}'> | ||||
| 	   				<input type='hidden' name='id' value='{{o.id}}'> | ||||
| 	   				<input type='hidden' name='scroll'> | ||||
| 	   				 | ||||
| 					{% if o.komentare %} | ||||
| 	   				<button name='action' value='del' type='button' | ||||
|             			title="Opravu nelze smazat – už ji někdo okomentoval"> | ||||
|                   <img src="{% static "korektury/imgs/delete-gr.png"%}"/> | ||||
| 	   				</button> | ||||
| 					{% else %} | ||||
| 					<button type='submit' name='action' value='del' title='Smaž opravu'> | ||||
|             <img src="{% static "korektury/imgs/delete.png"%}"/> | ||||
| 					</button> | ||||
| 					{% endif %} | ||||
| 					    | ||||
| 					{% if o.status = 'opraveno' or o.status = 'neni_chyba'  %} | ||||
| 					<button type='submit' name='action' value='undone' title='Označ jako neopravené'> | ||||
|             <img src="{% static "korektury/imgs/undo.png"%}"/> | ||||
| 					</button> | ||||
| 					{% else %} | ||||
| 					<button type='submit' name='action' value='done' title='Označ jako opravené'> | ||||
|             <img src="{% static "korektury/imgs/check.png"%}"/> | ||||
| 					</button> | ||||
| 					<button type='submit' name='action' value='wontfix' title='Označ jako irelevantní '> | ||||
|             <img src="{% static "korektury/imgs/cross.png" %}"/> | ||||
| 					</button> | ||||
| 					{% endif %} | ||||
| 				</form> | ||||
| 				<!-- /Existujici korektura !--> | ||||
| 						 | ||||
| 				{% if o.komentare %} | ||||
| 				<button type='button' title="Korekturu nelze upravit – už ji někdo okomentoval"> | ||||
|           <img src="{% static "korektury/imgs/edit-gr.png" %}"/> | ||||
| 				</button> | ||||
| 				{% else %} | ||||
| 				<button type='button' onclick='box_edit(this,"update");' title='Oprav opravu'> | ||||
|           <img src="{% static "korektury/imgs/edit.png" %}"/> | ||||
| 				</button> | ||||
| 				{% endif %} | ||||
| 				<button type='button' onclick='box_edit(this, "comment");' title='Komentovat'> | ||||
|           <img src="{% static "korektury/imgs/comment.png" %}"/> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div id='op{{o.id}}-text'>{{o.text}}</div> | ||||
| 
 | ||||
| 		{% for k in o.komentare %} | ||||
|     	<hr> | ||||
| 		<div class='comment' id='k{{k.id}}'> | ||||
|     		<div class='corr-header'> | ||||
|         		<div class='author'>{{k.autor}}</div> | ||||
|             	<div class="float-right"> | ||||
| 					<!-- Komentar !--> | ||||
|                     <form  action='' onsubmit='save_scroll(this)' method='POST'> | ||||
| 						{% csrf_token %} | ||||
|                     	<input type='hidden' name='pdf' value='{{pdf.id}}'> | ||||
| 						<input type='hidden' name='id' value='{{k.id}}'> | ||||
|                     	<input type='hidden' name='scroll'> | ||||
|                     	<button type='submit' name='action' value='del-comment' title='Smaž komentář' | ||||
|                       		onclick='return confirm("Opravdu smazat komentář?")'> | ||||
|               <img src="{% static "korektury/imgs/delete.png" %}"/> | ||||
| 					 	</button> | ||||
|                     </form> | ||||
| 					<!-- /Komentar !--> | ||||
| 					<button type='button' onclick='update_comment(this);' title='Uprav komentář'> | ||||
|             <img src="{% static "korektury/imgs/edit.png"%}"/> | ||||
| 					</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div id='kt{{k.id}}'>{{k.text}}</div> | ||||
| 		</div> | ||||
| 		{% endfor %}  | ||||
| 	</div>	 | ||||
| 	{% endfor %} | ||||
| 
 | ||||
| 	<script> | ||||
| 	{% for s in opravy_strany %} | ||||
| 		place_comments_one_div("img-{{s.strana}}", [{% for o in s.op_id %}["op{{o.id}}",{{o.x}},{{o.y}}],{% endfor %}[]]); | ||||
| 	{% endfor %} | ||||
| 	{% if scroll %} | ||||
| 		window.scrollTo(0,{{scroll}}); | ||||
| 	{% endif %} | ||||
| 	</script> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										22
									
								
								korektury/templates/korektury/seznam.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,22 @@ | |||
| {% extends "korektury/base.html" %} | ||||
| 
 | ||||
| {% block content %} | ||||
| 
 | ||||
| <h1> | ||||
| {% block nadpis1a %} | ||||
| {% block title %} | ||||
|   Korektury | ||||
| {% endblock title %} | ||||
| {% endblock nadpis1a %} | ||||
| </h1> | ||||
| 
 | ||||
| <ul> | ||||
|   {% for pdf in object_list  %} | ||||
| 	  <li> <b>{{ pdf.nazev }}</b> <i>{{pdf.komentar}}</i> <a href="/korektury/{{pdf.id}}">{{pdf.pdf.url}}</a> </li> | ||||
|   {% empty %} | ||||
|     <li> Nejsou žádné dokumenty ke korekturování. | ||||
|   {% endfor %} | ||||
| </ul> | ||||
| 
 | ||||
| 
 | ||||
| {% endblock content %} | ||||
							
								
								
									
										3
									
								
								korektury/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,3 @@ | |||
| from django.test import TestCase | ||||
| 
 | ||||
| # Create your tests here. | ||||
							
								
								
									
										12
									
								
								korektury/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,12 @@ | |||
| from django.conf.urls import *  # NOQA | ||||
| from django.conf.urls import patterns, url | ||||
| from django.contrib.auth.decorators import user_passes_test | ||||
| from . import views | ||||
| 
 | ||||
| staff_member_required = user_passes_test(lambda u: u.is_staff) | ||||
| 
 | ||||
| urlpatterns = patterns('', | ||||
|     url(r'^korektury/$', staff_member_required(views.KorekturyListView.as_view()), name='korektury-list'), | ||||
|     url(r'^korektury/(?P<pdf>\d+)/$', staff_member_required(views.KorekturyView.as_view()), name='korektury'), | ||||
|     url(r'^korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), | ||||
| ) | ||||
							
								
								
									
										165
									
								
								korektury/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,165 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from django.shortcuts import render | ||||
| from django.shortcuts import get_object_or_404, render | ||||
| from django.http import HttpResponseRedirect | ||||
| from django.http import HttpResponse | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.views import generic | ||||
| from django.utils.translation import ugettext as _ | ||||
| from django.http import Http404 | ||||
| from django.http import HttpResponseRedirect | ||||
| 
 | ||||
| from .models import Oprava,Komentar,KorekturovanePDF | ||||
| from .forms import OpravaForm | ||||
| 
 | ||||
| from datetime import timedelta, date, datetime | ||||
| from itertools import groupby | ||||
| import tempfile | ||||
| import subprocess | ||||
| import shutil | ||||
| import os | ||||
| from django.conf import settings | ||||
| import unicodedata | ||||
| 
 | ||||
| class KorekturyHelpView(generic.TemplateView): | ||||
|     template_name = 'korektury/help.html' | ||||
| 
 | ||||
| class KorekturyListView(generic.ListView): | ||||
|     model = KorekturovanePDF | ||||
|     template_name = 'korektury/seznam.html' | ||||
| 
 | ||||
| ### Korektury | ||||
| class KorekturyView(generic.TemplateView): | ||||
|     model = Oprava | ||||
|     template_name = 'korektury/opraf.html' | ||||
|     form_class = OpravaForm | ||||
| 
 | ||||
|     def post(self, request, *args, **kwargs): | ||||
|         form = self.form_class(request.POST) | ||||
|         q = request.POST | ||||
|         scroll = q.get('scroll') | ||||
|         autor = q.get('au') | ||||
|         print "autor:" + str(autor) | ||||
|         if not autor: | ||||
|             autor = 'anonym' | ||||
|         if not scroll: | ||||
|             scroll = 0 | ||||
| 
 | ||||
| 
 | ||||
|         action = q.get('action') | ||||
|         if (action == u''):  # Přidej | ||||
|             x = int(q.get('x')) | ||||
|             y = int(q.get('y')) | ||||
|             text = q.get('txt') | ||||
|             strana = int(q.get('img-id')[4:]) | ||||
|             pdf = KorekturovanePDF.objects.filter(id=q.get('pdf')).first() | ||||
| 
 | ||||
|             op = Oprava(x=x,y=y, autor=autor, text=text, strana=strana,pdf = pdf) | ||||
|             op.save() | ||||
|         elif (action == u'del'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             op.delete() | ||||
|         elif (action == u'update'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             text = q.get('txt') | ||||
|             op.autor = autor | ||||
|             op.text = text | ||||
|             op.save() | ||||
|         elif (action == u'undone'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             op.status = op.STATUS_K_OPRAVE | ||||
|             op.save() | ||||
|         elif (action == u'done'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             op.status = op.STATUS_OPRAVENO | ||||
|             op.save() | ||||
|         elif (action == u'wontfix'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             op.status = op.STATUS_NENI_CHYBA | ||||
|             op.save() | ||||
|         elif (action == u'comment'): | ||||
|             id = int(q.get('id')) | ||||
|             op = Oprava.objects.filter(id=id).first() | ||||
|             text = q.get('txt') | ||||
|             kom = Komentar(oprava=op,autor=autor,text=text) | ||||
|             kom.save() | ||||
|         elif (action == u'update-comment'): | ||||
|             id = int(q.get('id')) | ||||
|             kom = Komentar.objects.filter(id=id).first() | ||||
|             text = q.get('txt') | ||||
|             kom.text = text | ||||
|             kom.autor = autor | ||||
|             kom.save() | ||||
|         elif (action == u'del-comment'): | ||||
|             id = int(q.get('id')) | ||||
|             kom = Komentar.objects.filter(id=id).first() | ||||
|             kom.delete() | ||||
|         elif (action == u'delall'): | ||||
|             pdf = KorekturovanePDF.objects.filter(id=q.get('pdf')) | ||||
|             checked = q.get('yes') | ||||
|             if checked: | ||||
|                 opravy = Oprava.objects.filter(pdf=pdf) | ||||
|                 komentare = Komentar.objects.filter(oprava=opravy) | ||||
|                 opravy.delete() | ||||
|                 komentare.delete() | ||||
|         elif (action == u'set-state'): | ||||
|             pdf = KorekturovanePDF.objects.get(id=q.get('pdf')) | ||||
|             if (q.get('state') == u'adding'): | ||||
|                 pdf.status = pdf.STATUS_PRIDAVANI | ||||
|             elif (q.get('state') == u'comitting'): | ||||
|                 pdf.status = pdf.STATUS_ZANASENI | ||||
|             elif (q.get('state') == u'deprecated'): | ||||
|                 pdf.status = pdf.STATUS_ZASTARALE | ||||
|             pdf.save() | ||||
|              | ||||
| 
 | ||||
|              | ||||
| 
 | ||||
| #        return HttpResponse(u'Keys: %s '%(q.iteitems())) | ||||
| #        return HttpResponse(u'Oprav: %d, akce: %s'%( | ||||
| #            len(Oprava.objects.all()),action)) | ||||
|   | ||||
| #        return HttpResponseRedirect(reverse('korektury')+"?scroll=%s"%(scroll)) | ||||
|         context = self.get_context_data() | ||||
|         context['scroll'] = scroll | ||||
|         context['autor'] = autor | ||||
|         return render(request, 'korektury/opraf.html',context) | ||||
| #        return HttpResponse(u'Oprav: %d,x: %d y: %d, autor: %s, text: %s, strana: %d'%( | ||||
| #            len(Oprava.objects.all()),x,y,autor,text,strana)) | ||||
|     def get_context_data(self, **kwargs): | ||||
|         context = super(KorekturyView,self).get_context_data(**kwargs) | ||||
|         pdf = KorekturovanePDF.objects.filter(id=self.kwargs['pdf']).first() | ||||
|         context['pdf'] = pdf | ||||
|         context['img_name'] = os.path.split(pdf.pdf.path)[1].split('.')[0] | ||||
|         context['img_path'] = settings.KOREKTURY_IMG_DIR | ||||
|         context['img_indexes'] = range(pdf.stran)  | ||||
|         context['form_oprava'] = OpravaForm() | ||||
|         opravy = Oprava.objects.filter(pdf=self.kwargs['pdf']) | ||||
|         zasluhy = {} | ||||
|         for o in opravy: | ||||
|             if o.autor in zasluhy: | ||||
|                 zasluhy[o.autor]+=1 | ||||
|             else: | ||||
|                 zasluhy[o.autor]=1 | ||||
|             o.komentare = o.komentar_set.all() | ||||
|             for k in o.komentare: | ||||
|                 if k.autor in zasluhy: | ||||
|                     zasluhy[k.autor]+=1 | ||||
|                 else:  | ||||
|                     zasluhy[k.autor]=1 | ||||
| 
 | ||||
|         strany = opravy.values('strana') | ||||
|         opravy_na_stranu = [{'strana':s['strana'],'op_id':opravy.filter(strana=s['strana'])} for s in strany] | ||||
|         context['opravy_strany'] = opravy_na_stranu | ||||
|          | ||||
|         context['opravy'] = opravy | ||||
|         context['zasluhy'] = zasluhy | ||||
|         return context | ||||
|     def form_valid(self,form): | ||||
|         return super(KorekturyView,self).form_valid(form) | ||||
| 
 | ||||
|  | @ -42,6 +42,9 @@ STATICFILES_FINDERS = ( | |||
|     'django.contrib.staticfiles.finders.FileSystemFinder', | ||||
| ) | ||||
| 
 | ||||
| # Where redirect for login required services | ||||
| LOGIN_URL = '/admin/login' | ||||
| 
 | ||||
| # Modules configuration | ||||
| 
 | ||||
| AUTHENTICATION_BACKENDS = ( | ||||
|  | @ -117,6 +120,7 @@ INSTALLED_APPS = ( | |||
|     'mamweb', | ||||
|     'seminar', | ||||
|     'galerie', | ||||
|     'korektury', | ||||
| 
 | ||||
|     # Admin upravy: | ||||
| 
 | ||||
|  | @ -236,3 +240,5 @@ LOGGING = { | |||
| # MaM specific | ||||
| 
 | ||||
| SEMINAR_RESENI_DIR = os.path.join(BASE_DIR, 'media', 'reseni') | ||||
| KOREKTURY_PDF_DIR = os.path.join(BASE_DIR, 'media', 'korektury','pdf') | ||||
| KOREKTURY_IMG_DIR = os.path.join(BASE_DIR, 'media', 'korektury','img') | ||||
|  |  | |||
|  | @ -35,6 +35,13 @@ DATABASES = { | |||
|         'NAME': os.path.join(BASE_DIR, 'db-local.sqlite3'), | ||||
|     } | ||||
| } | ||||
| #DATABASES = { | ||||
| #    'default': { | ||||
| #        'ENGINE': 'django.db.backends.postgresql_psycopg2', | ||||
| #        'NAME': 'mam_local', | ||||
| #        'USER': 'mam', | ||||
| #    }, | ||||
| #} | ||||
| 
 | ||||
| # LOGGING | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,9 @@ urlpatterns = patterns('', | |||
|     # Seminarova aplikace (ma vlastni podadresare) | ||||
|     url(r'^', include('seminar.urls')), | ||||
|      | ||||
|     # Korekturovaci aplikace (ma vlastni podadresare) | ||||
|     url(r'^', include('korektury.urls')), | ||||
| 
 | ||||
|     # Comments (interni i verejne) | ||||
|     url(r'^comments_dj/', include('django_comments.urls')), | ||||
|     url(r'^comments_fl/', include('fluent_comments.urls')), | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from django.db import models | |||
| 
 | ||||
| from django.contrib.auth.models import User | ||||
| 
 | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Novinky, Organizator | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Novinky, Organizator | ||||
| import autocomplete_light | ||||
| 
 | ||||
| 
 | ||||
|  | @ -163,6 +163,19 @@ class Soustredeni_UcastniciInline(admin.TabularInline): | |||
|         qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) | ||||
|         return qs.select_related('resitel', 'soustredeni') | ||||
| 
 | ||||
| class Soustredeni_OrganizatoriInline(admin.TabularInline): | ||||
|     form = autocomplete_light.modelform_factory(Soustredeni_Organizatori, autocomplete_fields=['organizator'], fields=['organizator'],) | ||||
|     model = Soustredeni_Organizatori | ||||
|     fields = ['organizator', 'poznamka', ] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(Soustredeni_OrganizatoriInline, self).get_queryset(request) | ||||
|         return qs.select_related('organizator', 'soustredeni') | ||||
| 
 | ||||
| ### Resitel | ||||
| 
 | ||||
| class ResitelAdmin(VersionAdmin): | ||||
|  | @ -362,7 +375,7 @@ class SoustredeniAdmin(VersionAdmin): | |||
|         (u'Data',           {'fields': ['datum_zacatku', 'datum_konce']}), | ||||
|         ] | ||||
|     list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne'] | ||||
|     inlines = [Soustredeni_UcastniciInline] | ||||
|     inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline] | ||||
|     list_filter = ['typ', 'rocnik'] | ||||
|     view_on_site = Soustredeni.verejne_url | ||||
|     actions = [ | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| import autocomplete_light | ||||
| 
 | ||||
| from models import Skola, Resitel, Problem | ||||
| from models import Skola, Resitel, Problem, Organizator | ||||
| from taggit.models import Tag | ||||
| 
 | ||||
| 
 | ||||
|  | @ -64,6 +64,38 @@ class ResitelAutocomplete(autocomplete_light.AutocompleteModelBase): | |||
| 
 | ||||
| autocomplete_light.register(ResitelAutocomplete) | ||||
| 
 | ||||
| class OrganizatorAutocomplete(autocomplete_light.AutocompleteModelBase): | ||||
| 
 | ||||
|     model = Organizator | ||||
|      | ||||
|     search_fields=['user__first_name', 'user__last_name', 'prezdivka'] | ||||
| 
 | ||||
|     split_words = False | ||||
| 
 | ||||
|     limit_choices = 15 | ||||
| 
 | ||||
|     def choice_label(self, organizator): | ||||
|         return u"%s '%s' %s" % (organizator.user.first_name, | ||||
|                                 organizator.prezdivka, | ||||
|                                 organizator.user.last_name) | ||||
| 
 | ||||
|     attrs={ | ||||
|         # This will set the input placeholder attribute: | ||||
|         'placeholder': u'Organizátor', | ||||
|         # This will set the yourlabs.Autocomplete.minimumCharacters | ||||
|         # options, the naming conversion is handled by jQuery | ||||
|         'data-autocomplete-minimum-characters': 1, | ||||
|     } | ||||
| 
 | ||||
|     widget_attrs={ | ||||
|         'data-widget-maximum-values': 15, | ||||
|         # Enable modern-style widget ! | ||||
|         'class': 'modern-style', | ||||
|     } | ||||
| 
 | ||||
| autocomplete_light.register(OrganizatorAutocomplete) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class ProblemAutocomplete(autocomplete_light.AutocompleteModelBase): | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										36
									
								
								seminar/migrations/0036_add_org_to_soustredeni.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,36 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0035_django_imagekit'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='Soustredeni_Organizatori', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \xfa\u010dasti organiz\xe1tora (plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), | ||||
|                 ('organizator', models.ForeignKey(verbose_name='organiz\xe1tor', to='seminar.Organizator')), | ||||
|                 ('soustredeni', models.ForeignKey(verbose_name='soust\u0159ed\u011bn\xed', to='seminar.Soustredeni')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'ordering': ['soustredeni', 'organizator'], | ||||
|                 'db_table': 'seminar_soustredeni_organizatori', | ||||
|                 'verbose_name': '\xda\u010dast organiz\xe1tor\u016f na soust\u0159ed\u011bn\xed', | ||||
|                 'verbose_name_plural': '\xda\u010dasti organiz\xe1tor\u016f na soust\u0159ed\u011bn\xed', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='soustredeni', | ||||
|             name='organizatori', | ||||
|             field=models.ManyToManyField(help_text='Seznam organiz\xe1tor\u016f soust\u0159ed\u011bn\xed', to='seminar.Organizator', verbose_name='Organiz\xe1to\u0159i soust\u0159ed\u011bn\xed', through='seminar.Soustredeni_Organizatori'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
|  | @ -579,6 +579,51 @@ class PrilohaReseni(SeminarModelBase): | |||
|         return force_unicode(self.soubor) | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
| @python_2_unicode_compatible | ||||
| class Organizator(models.Model): | ||||
|     user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba', | ||||
|             help_text = 'Vyber účet spřažený s organizátorem.') | ||||
|     prezdivka = models.CharField('Přezdívka', max_length = 32, | ||||
|             null = True, blank = True) | ||||
|     organizuje_od_roku = models.IntegerField('Organizuje od roku', | ||||
|             null = True, blank = True) | ||||
|     organizuje_do_roku = models.IntegerField('Organizuje do roku', | ||||
|             null = True, blank = True) | ||||
|     studuje = models.CharField('Studium aj.', max_length = 256, | ||||
|             null = True, blank = True, | ||||
|             help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', " | ||||
|             "'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo " | ||||
|             "'Přednáší na MFF'") | ||||
|     strucny_popis_organizatora = models.TextField('Stručný popis organizátora', | ||||
|             null = True, blank = True) | ||||
|     foto = ProcessedImageField(verbose_name='Fotografie organizátora', | ||||
|             upload_to='image_organizatori/velke/%Y/', null = True, blank = True, | ||||
|             help_text = 'Vlož fotografii organizátora o libovolné velikosti', | ||||
|             processors=[ | ||||
|                 Transpose(Transpose.AUTO), | ||||
|                 ResizeToFit(500, 500, upscale=False) | ||||
|             ], | ||||
|             options={'quality': 95}) | ||||
|     foto_male = ImageSpecField(source='foto', | ||||
|             processors=[ | ||||
|                 ResizeToFit(200, 200, upscale=False) | ||||
|             ], | ||||
|             options={'quality': 95}) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         if self.prezdivka: | ||||
|             return u"%s '%s' %s" % (self.user.first_name, | ||||
|                                     self.prezdivka, | ||||
|                                     self.user.last_name) | ||||
|         else: | ||||
|             return u"%s %s" % (self.user.first_name, self.user.last_name) | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = 'Organizátor' | ||||
|         verbose_name_plural = 'Organizátoři' | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
| @python_2_unicode_compatible | ||||
| class Soustredeni(SeminarModelBase): | ||||
|  | @ -608,6 +653,11 @@ class Soustredeni(SeminarModelBase): | |||
|     ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění', | ||||
|         help_text=u'Seznam účastníků soustředění', through='Soustredeni_Ucastnici') | ||||
| 
 | ||||
|     organizatori = models.ManyToManyField(Organizator, | ||||
|             verbose_name=u'Organizátoři soustředění', | ||||
|             help_text=u'Seznam organizátorů soustředění', | ||||
|             through='Soustredeni_Organizatori') | ||||
| 
 | ||||
|     text = models.TextField(u'text k soustředění (HTML)', blank=True, default='') | ||||
| 
 | ||||
|     TYP_JARNI = 'jarni' | ||||
|  | @ -659,6 +709,30 @@ class Soustredeni_Ucastnici(models.Model): | |||
|         return force_unicode(u'%s na %s' % (self.resitel, self.soustredeni, )) | ||||
|         # NOTE: Poteciální DB HOG bez select_related | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
| @python_2_unicode_compatible | ||||
| class Soustredeni_Organizatori(models.Model): | ||||
| 
 | ||||
|     class Meta: | ||||
|         db_table = 'seminar_soustredeni_organizatori' | ||||
|         verbose_name = u'Účast organizátorů na soustředění' | ||||
|         verbose_name_plural = u'Účasti organizátorů na soustředění' | ||||
|         ordering = ['soustredeni', 'organizator'] | ||||
| 
 | ||||
|     # Interní ID | ||||
|     id = models.AutoField(primary_key = True) | ||||
| 
 | ||||
|     organizator = models.ForeignKey(Organizator, verbose_name=u'organizátor') | ||||
| 
 | ||||
|     soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění') | ||||
| 
 | ||||
|     poznamka = models.TextField(u'neveřejná poznámka', blank=True, | ||||
|         help_text=u'Neveřejná poznámka k účasti organizátora (plain text)') | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u'%s na %s' % (self.organizator, self.soustredeni, )) | ||||
|         # NOTE: Poteciální DB HOG bez select_related | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class VysledkyBase(SeminarModelBase): | ||||
|  | @ -778,41 +852,3 @@ class Novinky(models.Model): | |||
|         verbose_name_plural = 'Novinky' | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
| @python_2_unicode_compatible | ||||
| class Organizator(models.Model): | ||||
|     user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba', | ||||
|             help_text = 'Vyber účet spřažený s organizátorem.') | ||||
|     prezdivka = models.CharField('Přezdívka', max_length = 32, | ||||
|             null = True, blank = True) | ||||
|     organizuje_od_roku = models.IntegerField('Organizuje od roku', | ||||
|             null = True, blank = True) | ||||
|     organizuje_do_roku = models.IntegerField('Organizuje do roku', | ||||
|             null = True, blank = True) | ||||
|     studuje = models.CharField('Studium aj.', max_length = 256, | ||||
|             null = True, blank = True, | ||||
|             help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', " | ||||
|             "'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo " | ||||
|             "'Přednáší na MFF'") | ||||
|     strucny_popis_organizatora = models.TextField('Stručný popis organizátora', | ||||
|             null = True, blank = True) | ||||
|     foto = ProcessedImageField(verbose_name='Fotografie organizátora', | ||||
|             upload_to='image_organizatori/velke/%Y/', null = True, blank = True, | ||||
|             help_text = 'Vlož fotografii organizátora o libovolné velikosti', | ||||
|             processors=[ | ||||
|                 Transpose(Transpose.AUTO), | ||||
|                 ResizeToFit(500, 500, upscale=False) | ||||
|             ], | ||||
|             options={'quality': 95}) | ||||
|     foto_male = ImageSpecField(source='foto', | ||||
|             processors=[ | ||||
|                 ResizeToFit(200, 200, upscale=False) | ||||
|             ], | ||||
|             options={'quality': 95}) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return str(self.user) | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = 'Organizátor' | ||||
|         verbose_name_plural = 'Organizátoři' | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| {% load comments %} | ||||
| 
 | ||||
| {% block content %} | ||||
| <div> | ||||
| <div {% if not problem.verejne and user.is_staff %}class="mam-org-only"{% endif %}> | ||||
|   {% block problem %} | ||||
|   {% endblock %} | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,14 +8,10 @@ | |||
|     </h2> | ||||
|   {% if problem.cislo_zadani %} | ||||
|     <p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>. | ||||
|   {% endif %} | ||||
|   {% if problem.cislo_reseni %} | ||||
|     <p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>. | ||||
|   {% endif %} | ||||
|   {% else %} | ||||
|     {# TODO ? #} | ||||
|     <h2>Problém {{ problem.nazev }}</h2> | ||||
|   {% endif %} | ||||
| 
 | ||||
| 
 | ||||
|   <h3>Zadání</h3> | ||||
|   {{ problem.text_zadani |safe }} | ||||
|  |  | |||
|  | @ -60,16 +60,27 @@ | |||
|         {% autoescape off %}{{soustredeni.text}}{% endautoescape %} | ||||
|       {% endif %} | ||||
|       {% if user.is_authenticated %} | ||||
|       <div class="mam-org-only"> | ||||
|         {# Účastníci #} | ||||
|         <h3>Soustředění se zúčastnili tito účastníci:</h3> | ||||
|         <ul> | ||||
|         <p> | ||||
|         {% for i in soustredeni.soustredeni_ucastnici_set.all %} | ||||
|           <li>{{i.resitel}} | ||||
|           {{i.resitel}}{% if forloop.last %}.{% else %},{% endif %} | ||||
|         {% empty %} | ||||
|           <li>Nic! | ||||
|           Nic! | ||||
|         {% endfor %} | ||||
|         </ul> | ||||
|         </p> | ||||
|         <h3>Soustředění se účastnili tito organizátoři:</h3> | ||||
|         <p> | ||||
|         {% for i in soustredeni.soustredeni_organizatori_set.all %} | ||||
|           {{i.organizator}}{% if forloop.last %}.{% else %},{% endif %} | ||||
|         {% empty %} | ||||
|           Nic! | ||||
|         {% endfor %} | ||||
|         </p> | ||||
|       {% endif %} | ||||
|       </div> | ||||
| 
 | ||||
|       {% if not soustredeni.verejne_db and user.is_staff %} | ||||
|         </div> {# class="mam-org-only" #} | ||||
|       {% endif %} | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| # coding:utf-8 | ||||
| 
 | ||||
| from django.shortcuts import get_object_or_404, render | ||||
| from django.http import HttpResponseRedirect | ||||
| from django.http import HttpResponse | ||||
| from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.core.exceptions import PermissionDenied | ||||
| from django.views import generic | ||||
| from django.utils.translation import ugettext as _ | ||||
| from django.http import Http404 | ||||
|  | @ -235,11 +235,14 @@ class ProblemView(generic.DetailView): | |||
| 
 | ||||
|     def get_context_data(self, **kwargs): | ||||
|         context = super(ProblemView, self).get_context_data(**kwargs) | ||||
|         if not context['problem'].verejne() and not self.request.user.is_staff: | ||||
|             raise PermissionDenied() | ||||
|         if context['problem'].typ == Problem.TYP_RES_CLANEK: | ||||
|             context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni') | ||||
|         return context | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class RadekVysledkovky(object): | ||||
|     pass | ||||
| 
 | ||||
|  |  | |||
 Bc. Petr Pecha
						Bc. Petr Pecha