1 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 from catalogue.models import User
5 from django.db.models import Count
6 from django import forms
7 from django.utils.translation import ugettext_lazy as _
8 from django.conf import settings
10 from catalogue.constants import MASTERS
11 from catalogue.models import Book, Chunk, Image
13 class DocumentCreateForm(forms.ModelForm):
15 Form used for creating new documents.
17 file = forms.FileField(required=False)
18 text = forms.CharField(required=False, widget=forms.Textarea)
22 exclude = ['parent', 'parent_number', 'project']
24 def __init__(self, *args, **kwargs):
25 super(DocumentCreateForm, self).__init__(*args, **kwargs)
26 self.fields['slug'].widget.attrs={'class': 'autoslug'}
27 self.fields['gallery'].widget.attrs={'class': 'autoslug'}
28 self.fields['title'].widget.attrs={'class': 'autoslug-source'}
31 super(DocumentCreateForm, self).clean()
32 file = self.cleaned_data['file']
36 self.cleaned_data['text'] = file.read().decode('utf-8')
37 except UnicodeDecodeError:
38 raise forms.ValidationError(_("Text file must be UTF-8 encoded."))
40 if not self.cleaned_data["text"]:
41 self._errors["file"] = self.error_class([_("You must either enter text or upload a file")])
43 return self.cleaned_data
46 class DocumentsUploadForm(forms.Form):
48 Form used for uploading new documents.
50 file = forms.FileField(required=True, label=_('ZIP file'))
51 dirs = forms.BooleanField(label=_('Directories are documents in chunks'),
52 widget = forms.CheckboxInput(attrs={'disabled':'disabled'}))
55 file = self.cleaned_data['file']
59 z = self.cleaned_data['zip'] = zipfile.ZipFile(file)
60 except zipfile.BadZipfile:
61 raise forms.ValidationError("Should be a ZIP file.")
63 raise forms.ValidationError("ZIP file corrupt.")
65 return self.cleaned_data
68 class ChunkForm(forms.ModelForm):
70 Form used for editing a chunk.
72 user = forms.ModelChoiceField(queryset=
73 User.objects.annotate(count=Count('chunk')).
74 order_by('last_name', 'first_name'), required=False,
75 label=_('Assigned to'))
79 fields = ['title', 'slug', 'gallery_start', 'user', 'stage']
82 def __init__(self, *args, **kwargs):
83 super(ChunkForm, self).__init__(*args, **kwargs)
84 self.fields['gallery_start'].widget.attrs={'class': 'number-input'}
85 self.fields['slug'].widget.attrs={'class': 'autoslug'}
86 self.fields['title'].widget.attrs={'class': 'autoslug-source'}
89 slug = self.cleaned_data['slug']
91 chunk = Chunk.objects.get(book=self.instance.book, slug=slug)
92 except Chunk.DoesNotExist:
94 if chunk == self.instance:
96 raise forms.ValidationError(_('Chunk with this slug already exists'))
99 class ChunkAddForm(ChunkForm):
101 Form used for adding a chunk to a document.
104 def clean_slug(self):
105 slug = self.cleaned_data['slug']
107 user = Chunk.objects.get(book=self.instance.book, slug=slug)
108 except Chunk.DoesNotExist:
110 raise forms.ValidationError(_('Chunk with this slug already exists'))
113 class BookAppendForm(forms.Form):
115 Form for appending a book to another book.
116 It means moving all chunks from book A to book B and deleting A.
118 append_to = forms.ModelChoiceField(queryset=Book.objects.all(),
119 label=_("Append to"))
121 def __init__(self, book, *args, **kwargs):
122 ret = super(BookAppendForm, self).__init__(*args, **kwargs)
123 self.fields['append_to'].queryset = Book.objects.exclude(pk=book.pk)
127 class BookForm(forms.ModelForm):
128 """Form used for editing a Book."""
132 exclude = ['project']
134 def __init__(self, *args, **kwargs):
135 ret = super(BookForm, self).__init__(*args, **kwargs)
136 self.fields['slug'].widget.attrs.update({"class": "autoslug"})
137 self.fields['title'].widget.attrs.update({"class": "autoslug-source"})
140 def save(self, **kwargs):
141 orig_instance = Book.objects.get(pk=self.instance.pk)
142 old_gallery = orig_instance.gallery
143 new_gallery = self.cleaned_data['gallery']
144 if new_gallery != old_gallery:
147 from django.conf import settings
148 shutil.move(orig_instance.gallery_path(),
149 os.path.join(settings.MEDIA_ROOT, settings.IMAGE_DIR, new_gallery))
150 super(BookForm, self).save(**kwargs)
153 class ReadonlyBookForm(BookForm):
154 """Form used for not editing a Book."""
156 def __init__(self, *args, **kwargs):
157 ret = super(ReadonlyBookForm, self).__init__(*args, **kwargs)
158 for field in self.fields.values():
159 field.widget.attrs.update({"disabled": "disabled"})
163 class ChooseMasterForm(forms.Form):
165 Form used for fixing the chunks in a book.
168 master = forms.ChoiceField(choices=((m, m) for m in MASTERS))
171 class ImageForm(forms.ModelForm):
172 """Form used for editing an Image."""
173 user = forms.ModelChoiceField(queryset=
174 User.objects.annotate(count=Count('chunk')).
175 order_by('-count', 'last_name', 'first_name'), required=False,
176 label=_('Assigned to'))
180 fields = ['title', 'slug', 'user', 'stage']
182 def __init__(self, *args, **kwargs):
183 super(ImageForm, self).__init__(*args, **kwargs)
184 self.fields['slug'].widget.attrs={'class': 'autoslug'}
185 self.fields['title'].widget.attrs={'class': 'autoslug-source'}
188 class ReadonlyImageForm(ImageForm):
189 """Form used for not editing an Image."""
191 def __init__(self, *args, **kwargs):
192 super(ReadonlyImageForm, self).__init__(*args, **kwargs)
193 for field in self.fields.values():
194 field.widget.attrs.update({"disabled": "disabled"})
197 class MarkFinalForm(forms.Form):
198 username = forms.CharField(initial=settings.LITERARY_DIRECTOR_USERNAME)
199 comment = forms.CharField(initial=u'Ostateczna akceptacja merytoryczna przez kierownika literackiego.')
200 books = forms.CharField(widget=forms.Textarea, help_text=u'linki do książek w redakcji, po jednym na wiersz')
202 def clean_books(self):
203 books_value = self.cleaned_data['books']
204 slugs = [line.strip().strip('/').split('/')[-1] for line in books_value.split('\n') if line.strip()]
205 books = Book.objects.filter(slug__in=slugs)
206 if len(books) != len(slugs):
207 raise forms.ValidationError(
208 'Incorrect slug(s): %s' % ' '.join(slug for slug in slugs if not Book.objects.filter(slug=slug)))
211 def clean_username(self):
212 username = self.cleaned_data['username']
213 if not User.objects.filter(username=username):
214 raise forms.ValidationError('Invalid username')
218 for book in self.cleaned_data['books']:
219 for chunk in book.chunk_set.all():
220 src = chunk.head.materialize()
223 author=User.objects.get(username=self.cleaned_data['username']),
224 description=self.cleaned_data['comment'],
225 tags=[Chunk.tag_model.objects.get(slug='editor-proofreading')],
230 class PublishOptionsForm(forms.Form):
231 days = forms.IntegerField(label=u'po ilu dniach udostępnienić (0 = od razu)', min_value=0, initial=0)
232 beta = forms.BooleanField(label=u'Opublikuj na wersji testowej', required=False)