validate user data in gridftp
[qcg-portal.git] / filex / forms.py
index db6587b..f73b175 100644 (file)
@@ -1,9 +1,20 @@
 # coding=utf-8
+import os
+
 from django import forms
+from django.core.exceptions import ValidationError
+from django.core.validators import RegexValidator
 
 from filex.models import Favorite
 
 
+msg = u'Invalid value'
+host_validator = RegexValidator(r'^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+'
+                                r'(?:[a-zA-Z]{2,6}\.?|[a-zA-Z0-9-]{2,}(?<!-)\.?))(?::\d+)?$', msg)
+path_validator = RegexValidator(r'^/(?:[^/\0]+/?)*$', msg)
+name_validator = RegexValidator(r'^[^/\0]+$', msg)
+
+
 class FavoriteForm(forms.ModelForm):
     class Meta:
         model = Favorite
@@ -11,28 +22,121 @@ class FavoriteForm(forms.ModelForm):
         widgets = {'owner': forms.HiddenInput()}
 
 
-class NewDirForm(forms.Form):
-    host = forms.CharField(label=u'Host', max_length=256, widget=forms.HiddenInput())
-    path = forms.CharField(label=u'Ścieżka', max_length=1024, widget=forms.HiddenInput())
-    name = forms.CharField(label=u'Nazwa', max_length=256)
+class HostForm(forms.Form):
+    host = forms.CharField(label=u'Host', max_length=256, validators=[host_validator], widget=forms.HiddenInput())
+
+
+class HostPathForm(HostForm):
+    path = forms.CharField(label=u'Ścieżka', max_length=1024, validators=[path_validator], widget=forms.HiddenInput())
+
+    def clean_path(self):
+        return os.path.normpath(self.cleaned_data['path'])
+
+
+class HostPathNameForm(HostPathForm):
+    name = forms.CharField(label=u'Nazwa', max_length=256, validators=[name_validator])
+
+
+class HostItemsForm(HostForm):
+    dirs = forms.MultipleChoiceField(label=u'Katalogi', required=False, widget=forms.MultipleHiddenInput())
+    files = forms.MultipleChoiceField(label=u'Pliki', required=False, widget=forms.MultipleHiddenInput())
+
+    def __init__(self, data=None, *args, **kwargs):
+        super(HostItemsForm, self).__init__(data, *args, **kwargs)
+
+        if data is not None:
+            # accept user defined choices
+            self.fields['dirs'].choices += ((v, v) for v in data.getlist('dirs'))
+            self.fields['files'].choices += ((v, v) for v in data.getlist('files'))
+
+    def clean(self):
+        data = super(HostItemsForm, self).clean()
+
+        if not (data.get('dirs') or data.get('files')):
+            raise ValidationError('No items specified')
+
+        return data
+
+    @staticmethod
+    def _clean_paths(values):
+        errors, cleaned = [], []
+        for name in values:
+            try:
+                path_validator(name)
+            except ValidationError as e:
+                e.message += ' - ' + name
+                errors.append(e)
+            else:
+                cleaned.append(os.path.normpath(name))
+        if errors:
+            raise ValidationError(errors)
+
+        return cleaned
+
+    def clean_dirs(self):
+        return self._clean_paths(self.cleaned_data['dirs'])
+
+    def clean_files(self):
+        return self._clean_paths(self.cleaned_data['files'])
+    
+    
+class RenameForm(HostForm):
+    src = forms.CharField(label=u'Stara nazwa', max_length=1024, validators=[path_validator], widget=forms.HiddenInput())
+    dst = forms.CharField(label=u'Nowa nazwa', max_length=1024, validators=[path_validator])
+
+    def clean_src(self):
+        return os.path.normpath(self.cleaned_data['src'])
+
+    def clean_dst(self):
+        return os.path.normpath(self.cleaned_data['dst'])
+
+
+class ExtractForm(HostPathForm):
+    dst = forms.CharField(label=u'Katalog docelowy', max_length=1024, validators=[path_validator])
+
+    def clean_dst(self):
+        return os.path.normpath(self.cleaned_data['dst'])
+
+
+class CompressForm(HostPathForm):
+    archive = forms.CharField(label=u'Nazwa', max_length=1024, validators=[path_validator])
+    files = forms.MultipleChoiceField(label=u'Pliki', widget=forms.MultipleHiddenInput())
+
+    def __init__(self, data=None, *args, **kwargs):
+        super(CompressForm, self).__init__(data, *args, **kwargs)
+
+        if data is not None:
+            # accept user defined choices
+            self.fields['files'].choices += ((v, v) for v in data.getlist('files'))
+
+    def clean_files(self):
+        errors, cleaned = [], []
+        for name in self.cleaned_data['files']:
+            try:
+                name_validator(name)
+            except ValidationError as e:
+                e.message += ' - ' + name
+                errors.append(e)
+            else:
+                cleaned.append(os.path.normpath(name))
+        if errors:
+            raise ValidationError(errors)
 
+        return cleaned
 
-class RenameForm(forms.Form):
-    host = forms.CharField(label=u'Host', max_length=256, widget=forms.HiddenInput())
-    path = forms.CharField(label=u'Ścieżka', max_length=1024, widget=forms.HiddenInput())
-    src = forms.CharField(label=u'Stara nazwa', max_length=256, widget=forms.HiddenInput())
-    dst = forms.CharField(label=u'Nowa nazwa', max_length=256)
+    def clean_archive(self):
+        return os.path.normpath(self.cleaned_data['archive'])
 
 
-class ArchiveForm(NewDirForm):
+class ArchiveForm(CompressForm):
     ZIP = '.zip'
     GZIP = '.tar.gz'
     BZIP = '.tar.bz2'
 
     TYPE_CHOICES = (
-        (ZIP, 'Archiwum zip'),
-        (GZIP, 'Archiwum tar.gz'),
-        (BZIP, 'Archiwum tar.bz2'),
+        (ZIP, 'zip'),
+        (GZIP, 'tar.gz'),
+        (BZIP, 'tar.bz2'),
     )
 
-    type = forms.ChoiceField(label=u'Typ', choices=TYPE_CHOICES, initial=ZIP)
+    type = forms.ChoiceField(label=u'Typ archiwum', choices=TYPE_CHOICES, initial=ZIP)