update requirements
[redakcja.git] / apps / wiki / 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 import forms
7 from django.core.exceptions import ValidationError
8 from django.utils.translation import ugettext_lazy as _
9
10 from catalogue.constants import STAGES
11 from catalogue.models import Category
12 from catalogue.models.document import metadata_from_text
13 from librarian.document import Document
14
15
16 class DocumentTextSaveForm(forms.Form):
17     """
18     Form for saving document's text:
19
20         * parent_revision - revision which the modified text originated from.
21         * comment - user's verbose comment; will be used in commit.
22         * stage - change to this stage
23
24     """
25
26     parent_revision = forms.IntegerField(widget=forms.HiddenInput, required=False)
27     text = forms.CharField(widget=forms.HiddenInput)
28
29     author_name = forms.CharField(
30         required=True,
31         label=_(u"Author"),
32         help_text=_(u"Your name"),
33     )
34
35     author_email = forms.EmailField(
36         required=True,
37         label=_(u"Author's email"),
38         help_text=_(u"Your email address, so we can show a gravatar :)"),
39     )
40
41     comment = forms.CharField(
42         required=False,
43         widget=forms.Textarea,
44         label=_(u"Your comments"),
45         help_text=_(u"Describe changes you made."),
46     )
47
48     stage = forms.ChoiceField(
49         choices=STAGES,
50         required=False,
51         label=_(u"Stage"),
52         help_text=_(u"If completed a work stage, change to another one."),
53     )
54
55     def __init__(self, *args, **kwargs):
56         user = kwargs.pop('user')
57         super(DocumentTextSaveForm, self).__init__(*args, **kwargs)
58         if user and user.is_authenticated():
59             self.fields['author_name'].required = False
60             self.fields['author_email'].required = False
61
62     def clean_text(self):
63         text = self.cleaned_data['text']
64         try:
65             doc = Document.from_string(text)
66         except ValueError as e:
67             raise ValidationError(e.message)
68
69         from librarian import SSTNS, DCNS
70         root_elem = doc.edoc.getroot()
71         if len(root_elem) < 1 or root_elem[0].tag != SSTNS('metadata'):
72             raise ValidationError("The first tag in section should be metadata")
73         if len(root_elem) < 2 or root_elem[1].tag != SSTNS('header'):
74             raise ValidationError("The first tag after metadata should be header")
75         header = root_elem[1]
76         if not getattr(header, 'text', None) or not header.text.strip():
77             raise ValidationError(
78                 "The first header should contain the title in plain text (no links, emphasis etc.) and cannot be empty")
79
80         cover_url = doc.meta.get_one(DCNS('relation.coverimage.url'))
81         if cover_url:
82             ext = cover_url.rsplit('.', 1)[-1].lower()
83             if ext not in ('jpg', 'jpeg', 'png', 'gif', 'svg'):
84                 raise ValidationError('Invalid cover image format, should be an image file (jpg, png, gif, svg). '
85                                       'Change it in Metadata.')
86         metadata = metadata_from_text(text)
87         if 'multiple_values' in metadata:
88             raise ValidationError('Category "%s" does not allow multiple values.' % metadata['multiple_values'])
89         for category in Category.objects.all():
90             values = metadata.get(category.dc_tag)
91             if values is None:
92                 continue
93             if not category.multiple:
94                 values = [values]
95             if not values:
96                 values = []
97             for value in values:
98                 if not category.tag_set.filter(dc_value=value):
99                     raise ValidationError('Invalid value for dc:%s: %s' % (category.dc_tag, value))
100         return text
101
102
103 class DocumentTextRevertForm(forms.Form):
104     """
105     Form for reverting document's text:
106
107         * revision - revision to revert to.
108         * comment - user's verbose comment; will be used in commit.
109
110     """
111
112     revision = forms.IntegerField(widget=forms.HiddenInput)
113
114     author_name = forms.CharField(
115         required=False,
116         label=_(u"Author"),
117         help_text=_(u"Your name"),
118     )
119
120     author_email = forms.EmailField(
121         required=False,
122         label=_(u"Author's email"),
123         help_text=_(u"Your email address, so we can show a gravatar :)"),
124     )
125
126     comment = forms.CharField(
127         required=False,
128         widget=forms.Textarea,
129         label=_(u"Your comments"),
130         help_text=_(u"Describe the reason for reverting."),
131     )
132
133
134 class DocumentTextPublishForm(forms.Form):
135     revision = forms.IntegerField(widget=forms.HiddenInput)