e286a1d54d10f20e23dcbc29db82ef498a754e12
[redakcja.git] / apps / catalogue / forms.py
1 # -*- coding: utf-8 -*-
2 #
3 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 #
6 from django.utils.encoding import force_text
7 from django.utils.html import format_html
8 from django.utils.safestring import mark_safe
9
10 from catalogue.models import Category
11 from catalogue.models import Tag
12 from django import forms
13 from django.utils.translation import ugettext_lazy as _
14
15 from catalogue.constants import MASTERS
16
17
18 def tag_field(category_tag, required=True):
19     category = Category.objects.get(dc_tag=category_tag)
20     return forms.ModelMultipleChoiceField(queryset=category.tag_set.all(), required=required)
21
22
23 class DocumentCreateForm(forms.Form):
24     """
25         Form used for creating new documents.
26     """
27     owner_organization = forms.CharField(required=False)
28     title = forms.CharField()
29     language = forms.CharField()
30     publisher = forms.CharField(required=False)
31     description = forms.CharField(required=False)
32     rights = forms.CharField(required=False)
33     audience = forms.CharField()
34     
35     cover = forms.FileField(required=False)
36
37     def clean_cover(self):
38         cover = self.cleaned_data['cover']
39         if cover and cover.name.rsplit('.', 1)[-1].lower() not in ('jpg', 'jpeg', 'png', 'gif', 'svg'):
40             raise forms.ValidationError(_('The cover should be an image file (jpg/png/gif)'))
41         return file
42
43
44 class TagForm(forms.Form):
45     def __init__(self, category, instance=None, tutorial_no=None, *args, **kwargs):
46         super(TagForm, self).__init__(*args, **kwargs)
47         self.category = category
48         self.instance = instance
49         self.field().queryset = Tag.objects.filter(category=self.category)
50         self.field().label = self.category.label.capitalize()
51         if tutorial_no and category.tutorial:
52             self.field().widget.attrs.update({
53                 'data-toggle': 'tutorial',
54                 'data-tutorial': str(tutorial_no),
55                 'data-placement': 'bottom',
56                 'data-content': category.tutorial,
57             })
58         if self.instance:
59             self.field().initial = self.initial()
60
61     def save(self):
62         assert self.instance, 'No instance provided'
63         self.instance.tags.remove(*self.instance.tags.filter(category=self.category))
64         self.instance.tags.add(self.cleaned_tags())
65
66     def field(self):
67         raise NotImplementedError
68
69     def initial(self):
70         raise NotImplementedError
71
72     def cleaned_tags(self):
73         raise NotImplementedError
74
75
76 class TagSelect(forms.Select):
77     def render_option(self, selected_choices, option_value, option_label):
78         if option_value is None:
79             option_value = ''
80         help_html = ''
81         if option_value:
82             tag = Tag.objects.get(id=int(option_value))
83             if tag.help_text:
84                 help_html = mark_safe(' data-help="%s"' % tag.help_text)
85         option_value = force_text(option_value)
86         if option_value in selected_choices:
87             selected_html = mark_safe(' selected="selected"')
88             if not self.allow_multiple_selected:
89                 # Only allow for a single selection.
90                 selected_choices.remove(option_value)
91         else:
92             selected_html = ''
93         return format_html(
94             u'<option value="{}"{}{}>{}</option>',
95             option_value, selected_html, help_html, force_text(option_label))
96
97
98 class TagSingleForm(TagForm):
99     tag = forms.ModelChoiceField(
100         Tag.objects.none(),
101         widget=TagSelect(attrs={
102             'class': 'form-control',
103         })
104     )
105
106     def field(self):
107         return self.fields['tag']
108
109     def initial(self):
110         return self.instance.tags.get(category=self.category)
111
112     def cleaned_tags(self):
113         return [self.cleaned_data['tag']]
114
115
116 class TagMultipleForm(TagForm):
117     tags = forms.ModelMultipleChoiceField(
118         Tag.objects.none(), required=False,
119         widget=forms.SelectMultiple(attrs={
120             'class': 'chosen-select',
121             'data-placeholder': _('Choose'),
122         }))
123
124     def field(self):
125         return self.fields['tags']
126
127     def initial(self):
128         return self.instance.tags.filter(category=self.category)
129
130     def cleaned_tags(self):
131         return self.cleaned_data['tags']
132
133
134 class DocumentsUploadForm(forms.Form):
135     """
136         Form used for uploading new documents.
137     """
138     file = forms.FileField(required=True, label=_('ZIP file'))
139     dirs = forms.BooleanField(
140         label=_('Directories are documents in chunks'),
141         widget=forms.CheckboxInput(attrs={'disabled': 'disabled'}))
142
143     def clean(self):
144         file = self.cleaned_data['file']
145
146         import zipfile
147         try:
148             z = self.cleaned_data['zip'] = zipfile.ZipFile(file)
149         except zipfile.BadZipfile:
150             raise forms.ValidationError("Should be a ZIP file.")
151         if z.testzip():
152             raise forms.ValidationError("ZIP file corrupt.")
153
154         return self.cleaned_data
155
156
157 class ChooseMasterForm(forms.Form):
158     """
159         Form used for fixing the chunks in a book.
160     """
161
162     master = forms.ChoiceField(choices=((m, m) for m in MASTERS))
163
164
165 class DocumentForkForm(forms.Form):
166     """
167         Form used for forking documents.
168     """
169     owner_organization = forms.CharField(required=False)