diff --git a/.gitignore b/.gitignore index aefe158b..6b8b5c02 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ # secrets /django.secret + +# vim tmp files +*~ diff --git a/korektury/TODO b/korektury/TODO new file mode 100644 index 00000000..92c4b8d5 --- /dev/null +++ b/korektury/TODO @@ -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? + + diff --git a/korektury/__init__.py b/korektury/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/korektury/admin.py b/korektury/admin.py new file mode 100644 index 00000000..564e2cd0 --- /dev/null +++ b/korektury/admin.py @@ -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) diff --git a/korektury/forms.py b/korektury/forms.py new file mode 100644 index 00000000..676d6b3a --- /dev/null +++ b/korektury/forms.py @@ -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) + diff --git a/korektury/migrations/0001_initial.py b/korektury/migrations/0001_initial.py new file mode 100644 index 00000000..22643689 --- /dev/null +++ b/korektury/migrations/0001_initial.py @@ -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,), + ), + ] diff --git a/korektury/migrations/0002_auto_20151202_2351.py b/korektury/migrations/0002_auto_20151202_2351.py new file mode 100644 index 00000000..ba88f7c7 --- /dev/null +++ b/korektury/migrations/0002_auto_20151202_2351.py @@ -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', + ), + ] diff --git a/korektury/migrations/0003_auto_20151204_1855.py b/korektury/migrations/0003_auto_20151204_1855.py new file mode 100644 index 00000000..8f8cb70b --- /dev/null +++ b/korektury/migrations/0003_auto_20151204_1855.py @@ -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, + ), + ] diff --git a/korektury/migrations/0004_auto_20151204_2240.py b/korektury/migrations/0004_auto_20151204_2240.py new file mode 100644 index 00000000..ed47ccaf --- /dev/null +++ b/korektury/migrations/0004_auto_20151204_2240.py @@ -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, + ), + ] diff --git a/korektury/migrations/0005_auto_20151204_2244.py b/korektury/migrations/0005_auto_20151204_2244.py new file mode 100644 index 00000000..52ebdfb6 --- /dev/null +++ b/korektury/migrations/0005_auto_20151204_2244.py @@ -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, + ), + ] diff --git a/korektury/migrations/0006_oprava_pdf.py b/korektury/migrations/0006_oprava_pdf.py new file mode 100644 index 00000000..2adf04e7 --- /dev/null +++ b/korektury/migrations/0006_oprava_pdf.py @@ -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, + ), + ] diff --git a/korektury/migrations/__init__.py b/korektury/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/korektury/models.py b/korektury/models.py new file mode 100644 index 00000000..ee873616 --- /dev/null +++ b/korektury/models.py @@ -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)) + + + diff --git a/korektury/static/korektury/help.html b/korektury/static/korektury/help.html new file mode 100644 index 00000000..e10365f3 --- /dev/null +++ b/korektury/static/korektury/help.html @@ -0,0 +1,46 @@ + + + + Nápověda ke korigovátku + + +

Nápověda ke korigovátku

+

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é. +

Použití

+

+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. +

+Pokud chci korekturu okomentovat, kliknu na ikonu , +napíši komentář a kliknu na Oprav! (nebo Ctrl-Enter). Komentář se zobrazí pod +původní korekturou. +

+

Tlačítka u korektury

+ +

Stavy

+

Korektura

+ +

PDF

+ + diff --git a/korektury/static/korektury/imgs/check.png b/korektury/static/korektury/imgs/check.png new file mode 100644 index 00000000..c4d5504e Binary files /dev/null and b/korektury/static/korektury/imgs/check.png differ diff --git a/korektury/static/korektury/imgs/comment.png b/korektury/static/korektury/imgs/comment.png new file mode 100644 index 00000000..4a648425 Binary files /dev/null and b/korektury/static/korektury/imgs/comment.png differ diff --git a/korektury/static/korektury/imgs/cross.png b/korektury/static/korektury/imgs/cross.png new file mode 100644 index 00000000..f3add6aa Binary files /dev/null and b/korektury/static/korektury/imgs/cross.png differ diff --git a/korektury/static/korektury/imgs/delete-gr.png b/korektury/static/korektury/imgs/delete-gr.png new file mode 100644 index 00000000..d0ed643c Binary files /dev/null and b/korektury/static/korektury/imgs/delete-gr.png differ diff --git a/korektury/static/korektury/imgs/delete.png b/korektury/static/korektury/imgs/delete.png new file mode 100644 index 00000000..9b77ca3b Binary files /dev/null and b/korektury/static/korektury/imgs/delete.png differ diff --git a/korektury/static/korektury/imgs/edit-gr.png b/korektury/static/korektury/imgs/edit-gr.png new file mode 100644 index 00000000..e7ca04b8 Binary files /dev/null and b/korektury/static/korektury/imgs/edit-gr.png differ diff --git a/korektury/static/korektury/imgs/edit.png b/korektury/static/korektury/imgs/edit.png new file mode 100644 index 00000000..95cabe7d Binary files /dev/null and b/korektury/static/korektury/imgs/edit.png differ diff --git a/korektury/static/korektury/imgs/link.png b/korektury/static/korektury/imgs/link.png new file mode 100644 index 00000000..cfa343c7 Binary files /dev/null and b/korektury/static/korektury/imgs/link.png differ diff --git a/korektury/static/korektury/imgs/next-gr.png b/korektury/static/korektury/imgs/next-gr.png new file mode 100644 index 00000000..885c2cd7 Binary files /dev/null and b/korektury/static/korektury/imgs/next-gr.png differ diff --git a/korektury/static/korektury/imgs/next.png b/korektury/static/korektury/imgs/next.png new file mode 100644 index 00000000..e8b15f66 Binary files /dev/null and b/korektury/static/korektury/imgs/next.png differ diff --git a/korektury/static/korektury/imgs/undo.png b/korektury/static/korektury/imgs/undo.png new file mode 100644 index 00000000..973b5939 Binary files /dev/null and b/korektury/static/korektury/imgs/undo.png differ diff --git a/korektury/static/korektury/opraf.css b/korektury/static/korektury/opraf.css new file mode 100644 index 00000000..18da5f5a --- /dev/null +++ b/korektury/static/korektury/opraf.css @@ -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; +} + diff --git a/korektury/static/korektury/opraf.js b/korektury/static/korektury/opraf.js new file mode 100644 index 00000000..d39c0797 --- /dev/null +++ b/korektury/static/korektury/opraf.js @@ -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,'"') + ); +}; + diff --git a/korektury/static/korektury/png/.gitignore b/korektury/static/korektury/png/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/korektury/static/korektury/png/.gitignore @@ -0,0 +1 @@ +* diff --git a/korektury/static/korektury/tmp/.gitignore b/korektury/static/korektury/tmp/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/korektury/static/korektury/tmp/.gitignore @@ -0,0 +1 @@ +* diff --git a/korektury/templates/korektury/opraf.html b/korektury/templates/korektury/opraf.html new file mode 100644 index 00000000..bb354a7e --- /dev/null +++ b/korektury/templates/korektury/opraf.html @@ -0,0 +1,185 @@ + + + + + + Korektury {{pdf.nazev}} + + +

Korektury {{pdf.nazev}}

+ {% if pdf.status = 'zanaseni' %}

Probíhá zanášení korektur, zvažte, zda chcete přidávat nové

{% endif %} + {% if pdf.status = 'zastarale' %}

Toto PDF je již zastaralé, nepřidávejte nové korektury

{% endif %} + {{pdf.komentar}} +
+ Klikni na chybu, napiš komentář | + ls | + help |          | + hlavní stránka | + wiki | +
+ +
+ +
+ {% csrf_token %} + + + +
+ +
+ + + + + + + +
+ +
+ + {% for i in img_indexes %} +
+ +
+
+ {% endfor %} + + +
+ {% csrf_token %} + + + + Souhlasím se smazáním všech kometářů +
+ +
+

Změnit stav PDF:

+ Aktuální: {{pdf.status}} +
+ +
+ {% csrf_token %} + + + Přidávání korektur +
+ Zanášení korektur +
+ Zastaralé, nekorigovat +
+ +
+ + +
+

+ Děkujeme opravovatelům: {% for autor,pocet in zasluhy.items %} {{autor}}({{pocet}}) {% endfor %}

+
+ + {% for o in opravy %} +
+
+
+ +
+
{{o.autor}}
+
+ +
+ {% csrf_token %} + + + + + + {% if o.komentare %} + + {% else %} + + {% endif %} + + {% if o.status = 'opraveno' or o.status = 'neni_chyba' %} + + {% else %} + + + {% endif %} +
+ + + {% if o.komentare %} + + {% else %} + + {% endif %} + +
+
+
{{o.text}}
+ + {% for k in o.komentare %} +
+
+
+
{{k.autor}}
+
+ +
+ {% csrf_token %} + + + + +
+ + +
+
+
{{k.text}}
+
+ {% endfor %} +
+ {% endfor %} + + + + diff --git a/korektury/templates/korektury/seznam.html b/korektury/templates/korektury/seznam.html new file mode 100644 index 00000000..a74ae664 --- /dev/null +++ b/korektury/templates/korektury/seznam.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block content %} + +

+{% block nadpis1a %} + Korektury +{% endblock nadpis1a %} +

+ + + + +{% endblock content %} diff --git a/korektury/tests.py b/korektury/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/korektury/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/korektury/urls.py b/korektury/urls.py new file mode 100644 index 00000000..c2218035 --- /dev/null +++ b/korektury/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import * # NOQA +from django.conf.urls import patterns, url +from django.contrib.auth.decorators import permission_required +from . import views + +urlpatterns = patterns('', + url(r'^korektury$',permission_required('is_staff')(views.KorekturyListView.as_view()),name='korektury-list'), + url(r'^korektury/(?P\d+)$', permission_required('is_staff')(views.KorekturyView.as_view()), name='korektury'), +) diff --git a/korektury/views.py b/korektury/views.py new file mode 100644 index 00000000..48b57820 --- /dev/null +++ b/korektury/views.py @@ -0,0 +1,163 @@ +# -*- 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 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) + diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 67072e59..d3eaabb5 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -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') diff --git a/mamweb/settings_local.py b/mamweb/settings_local.py index 5ac59cd0..68030cdd 100644 --- a/mamweb/settings_local.py +++ b/mamweb/settings_local.py @@ -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 diff --git a/mamweb/urls.py b/mamweb/urls.py index 999ffc90..223bdae8 100644 --- a/mamweb/urls.py +++ b/mamweb/urls.py @@ -14,6 +14,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')),