0003-add-support-for-file-validation-8402.patch
tests/conftest.py | ||
---|---|---|
1 |
import os |
|
2 |
import ConfigParser |
|
3 | ||
1 | 4 |
import pytest |
2 | 5 | |
3 | 6 |
def pytest_addoption(parser): |
... | ... | |
7 | 10 |
def pytest_runtest_setup(item): |
8 | 11 |
if 'postgresql' in item.keywords and item.config.option.without_postgresql_tests is True: |
9 | 12 |
pytest.skip('skipped (PostgreSQL are disabled on command line)') |
13 | ||
14 |
@pytest.fixture |
|
15 |
def fargo_url(request, pub): |
|
16 |
config = ConfigParser.ConfigParser() |
|
17 |
path = os.path.join(pub.app_dir, 'site-options.cfg') |
|
18 |
url = 'http://fargo.example.net/' |
|
19 |
if os.path.exists(path): |
|
20 |
config.read([path]) |
|
21 |
if not config.has_section('options'): |
|
22 |
config.add_section('options') |
|
23 |
config.set('options', 'fargo_url', url) |
|
24 |
with file(path, 'w') as site_option: |
|
25 |
config.write(site_option) |
|
26 | ||
27 |
def fin(): |
|
28 |
config = ConfigParser.ConfigParser() |
|
29 |
if os.path.exists(path): |
|
30 |
config.read([path]) |
|
31 |
config.remove_option('options', 'fargo_url') |
|
32 |
with file(path, 'w') as site_option: |
|
33 |
config.write(site_option) |
|
34 |
request.addfinalizer(fin) |
|
35 |
return url |
tests/test_backoffice_pages.py | ||
---|---|---|
4 | 4 |
import re |
5 | 5 |
import shutil |
6 | 6 |
import StringIO |
7 |
import hashlib |
|
7 | 8 | |
8 | 9 |
import pytest |
10 |
from webtest import Upload |
|
11 |
import mock |
|
9 | 12 | |
10 | 13 |
from quixote import cleanup, get_publisher |
11 | 14 |
from wcs.qommon import errors, sessions |
... | ... | |
935 | 938 |
assert '>cat1<' in resp.body |
936 | 939 |
assert '>Misc<' in resp.body |
937 | 940 |
assert resp.body.index('>Misc<') < resp.body.index('>cat1<') |
941 | ||
942 | ||
943 |
def test_backoffice_file_field_validation(pub, fargo_url): |
|
944 |
user = create_user(pub, is_admin=True) |
|
945 |
user.name_identifiers = ['12345'] |
|
946 |
user.store() |
|
947 |
FormDef.wipe() |
|
948 |
formdef = FormDef() |
|
949 |
formdef.name = 'form title' |
|
950 |
formdef.fields = [fields.FileField( |
|
951 |
id='0', label='1st field', type='file', |
|
952 |
document_type={ |
|
953 |
'id': 'justificatif-de-domicile', |
|
954 |
'fargo': True, |
|
955 |
'mimetypes': ['application/pdf'], |
|
956 |
'label': 'PDF files', |
|
957 |
}) |
|
958 |
] |
|
959 |
formdef.store() |
|
960 |
formdef.data_class().wipe() |
|
961 |
upload = Upload('test.pdf', 'foobar', 'application/pdf') |
|
962 |
digest = hashlib.sha256('foobar').hexdigest() |
|
963 |
app = login(get_app(pub)) |
|
964 |
resp = app.get('/form-title/') |
|
965 |
resp.forms[0]['f0$file'] = upload |
|
966 |
resp = resp.forms[0].submit('submit') |
|
967 |
assert 'Check values then click submit.' in resp.body |
|
968 |
resp = resp.forms[0].submit('submit') |
|
969 |
assert resp.status_int == 302 |
|
970 |
with mock.patch('wcs.file_validation.http_get_page') as http_get_page: |
|
971 |
json_response = json.dumps({ |
|
972 |
'err': 0, |
|
973 |
'data': { |
|
974 |
'type': 'justificatif-de-domicile', |
|
975 |
'label': 'Justificatif de domicile', |
|
976 |
'creator': 'Jean Bono', |
|
977 |
'created': '2014-01-01T01:01:01', |
|
978 |
'start': '2014-01-01T01:01:01', |
|
979 |
'end': '2014-01-01T01:01:01', |
|
980 |
'metadata': [{ |
|
981 |
'name': 'code_postal', |
|
982 |
'label': 'Code postal', |
|
983 |
'value': '13400', |
|
984 |
}], |
|
985 |
}, |
|
986 |
}) |
|
987 |
http_get_page.return_value = None, 200, json_response, None |
|
988 |
resp = app.get('/backoffice/management/form-title/1/') |
|
989 |
http_get_page.assert_called_once_with('http://fargo.example.net/metadata/12345/c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2/justificatif-de-domicile/') |
|
990 |
assert 'class="value valid"' in resp.body |
|
991 |
assert 'Justificatif de domicile validated by Jean Bono on 2014-01-01T01:01:01' in resp.body |
|
992 |
assert 'Code postal: 13400' in resp.body |
|
993 |
assert 'Valid from 2014-01-01T01:01:01 to 2014-01-01T01:01:01' in resp.body |
tests/test_form_pages.py | ||
---|---|---|
1 |
import json |
|
1 | 2 |
import pytest |
2 | 3 |
import hashlib |
3 | 4 |
import os |
... | ... | |
7 | 8 |
import zipfile |
8 | 9 |
import base64 |
9 | 10 |
from webtest import Upload |
11 |
import mock |
|
10 | 12 | |
11 | 13 |
from quixote.http_request import Upload as QuixoteUpload |
12 | 14 |
from wcs.qommon.form import UploadedFile |
... | ... | |
1912 | 1914 |
assert formdef.data_class().count() == 1 |
1913 | 1915 |
assert formdef.data_class().select()[0].data['1'] == 'foobar3' |
1914 | 1916 |
assert formdef.data_class().select()[0].data['3'] == 'xxx3' |
1917 | ||
1918 | ||
1919 |
def test_file_field_validation(pub, fargo_url): |
|
1920 |
user = create_user(pub) |
|
1921 |
user.name_identifiers = ['12345'] |
|
1922 |
user.store() |
|
1923 |
FormDef.wipe() |
|
1924 |
formdef = FormDef() |
|
1925 |
formdef.name = 'form title' |
|
1926 |
formdef.fields = [fields.FileField( |
|
1927 |
id='0', label='1st field', type='file', |
|
1928 |
document_type={ |
|
1929 |
'id': 'justificatif-de-domicile', |
|
1930 |
'fargo': True, |
|
1931 |
'mimetypes': ['application/pdf'], |
|
1932 |
'label': 'PDF files', |
|
1933 |
}) |
|
1934 |
] |
|
1935 |
formdef.store() |
|
1936 |
formdef.data_class().wipe() |
|
1937 |
upload = Upload('test.pdf', 'foobar', 'application/pdf') |
|
1938 |
digest = hashlib.sha256('foobar').hexdigest() |
|
1939 |
app = login(get_app(pub), username='foo', password='foo') |
|
1940 |
resp = app.get('/form-title/') |
|
1941 |
resp.forms[0]['f0$file'] = upload |
|
1942 |
resp = resp.forms[0].submit('submit') |
|
1943 |
assert 'Check values then click submit.' in resp.body |
|
1944 |
resp = resp.forms[0].submit('submit') |
|
1945 |
assert resp.status_int == 302 |
|
1946 |
with mock.patch('wcs.file_validation.http_get_page') as http_get_page: |
|
1947 |
json_response = json.dumps({ |
|
1948 |
'err': 0, |
|
1949 |
'data': { |
|
1950 |
'type': 'justificatif-de-domicile', |
|
1951 |
'label': 'Justificatif de domicile', |
|
1952 |
'creator': 'Jean Bono', |
|
1953 |
'created': '2014-01-01T01:01:01', |
|
1954 |
'start': '2014-01-01T01:01:01', |
|
1955 |
'end': '2014-01-01T01:01:01', |
|
1956 |
'metadata': [{ |
|
1957 |
'name': 'code_postal', |
|
1958 |
'label': 'Code postal', |
|
1959 |
'value': '13400', |
|
1960 |
}], |
|
1961 |
}, |
|
1962 |
}) |
|
1963 |
http_get_page.return_value = None, 200, json_response, None |
|
1964 |
resp = resp.follow() |
|
1965 |
http_get_page.assert_called_once_with('http://fargo.example.net/metadata/12345/c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2/justificatif-de-domicile/') |
|
1966 |
http_get_page.reset_mock() |
|
1967 |
assert 'The form has been recorded' in resp.body |
|
1968 |
assert 'class="value valid"' in resp.body |
tests/test_formdef.py | ||
---|---|---|
4 | 4 | |
5 | 5 |
import pytest |
6 | 6 | |
7 |
from mock import patch |
|
8 | ||
7 | 9 |
from quixote import cleanup |
8 | 10 |
from wcs import formdef |
9 | 11 |
from wcs.formdef import FormDef |
10 | 12 |
from wcs.workflows import Workflow |
11 |
from wcs.fields import StringField |
|
13 |
from wcs.fields import StringField, FileField
|
|
12 | 14 | |
13 | 15 |
from utilities import create_temporary_pub |
14 | 16 | |
... | ... | |
132 | 134 | |
133 | 135 |
with pytest.raises(AttributeError): |
134 | 136 |
assert substs.foobar |
137 | ||
138 |
def test_file_field_migration(): |
|
139 |
with patch('wcs.file_validation.get_document_types') as get_document_types: |
|
140 |
get_document_types.return_value = { |
|
141 |
'justificatif-de-domicile': { |
|
142 |
'id': 'justificatif-de-domicile', |
|
143 |
'label': 'Justificatif de domicile', |
|
144 |
'fargo': True, |
|
145 |
}, |
|
146 |
} |
|
147 |
FormDef.wipe() |
|
148 |
formdef = FormDef() |
|
149 |
formdef.name = 'foo' |
|
150 |
file_type = ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] |
|
151 |
formdef.fields = [FileField(type='file', id='1', label='file')] |
|
152 |
formdef.fields[0].__dict__['file_type'] = file_type |
|
153 |
formdef.store() |
|
154 |
formdef = FormDef.get(1) |
|
155 |
assert 'file_type' not in formdef.fields[0].__dict__ |
|
156 |
assert formdef.fields[0].document_type |
|
157 |
assert formdef.fields[0].document_type['id'] == '_legacy' |
|
158 |
assert formdef.fields[0].document_type['mimetypes'] == ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] |
|
159 |
assert formdef.fields[0].document_type['label'] == ','.join(file_type) |
tests/test_formdef_import.py | ||
---|---|---|
227 | 227 |
cat.store() |
228 | 228 |
assert FormDef.import_from_xml_tree(formdef_xml_with_id, include_id=False).category_id == '2' |
229 | 229 |
assert FormDef.import_from_xml_tree(formdef_xml_with_id, include_id=True).category_id is None |
230 | ||
231 | ||
232 |
def test_file_field(): |
|
233 |
formdef = FormDef() |
|
234 |
formdef.name = 'foo' |
|
235 |
formdef.fields = [fields.FileField(type='file', id='1', document_type={ |
|
236 |
'id': 'justificatif-de-domicile', |
|
237 |
'fargo': True, |
|
238 |
'mimetypes': ['application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'image/*'], |
|
239 |
})] |
|
240 |
assert_xml_import_export_works(formdef, include_id=True) |
|
241 |
assert_xml_import_export_works(formdef) |
|
242 |
assert_json_import_export_works(formdef, include_id=True) |
|
243 |
assert_json_import_export_works(formdef) |
wcs/fields.py | ||
---|---|---|
30 | 30 |
from qommon.strftime import strftime |
31 | 31 | |
32 | 32 |
import data_sources |
33 |
import file_validation |
|
33 | 34 | |
34 | 35 | |
35 | 36 |
class PrefillSelectionWidget(CompositeWidget): |
... | ... | |
674 | 675 |
class FileField(WidgetField): |
675 | 676 |
key = 'file' |
676 | 677 |
description = N_('File Upload') |
677 |
file_type = []
|
|
678 |
document_type = None
|
|
678 | 679 |
max_file_size = None |
679 | 680 | |
680 | 681 |
widget_class = FileWithPreviewWidget |
681 | 682 |
extra_attributes = ['file_type', 'max_file_size'] |
682 | 683 | |
684 |
def __init__(self, *args, **kwargs): |
|
685 |
super(FileField, self).__init__(*args, **kwargs) |
|
686 |
self.document_type = self.document_type or {} |
|
687 | ||
688 |
@property |
|
689 |
def file_type(self): |
|
690 |
return (self.document_type or {}).get('mimetypes', []) |
|
691 | ||
683 | 692 |
def fill_admin_form(self, form): |
684 | 693 |
WidgetField.fill_admin_form(self, form) |
685 |
file_types = [ |
|
686 |
('audio/*', _('Sound files')), |
|
687 |
('video/*', _('Video files')), |
|
688 |
('image/*', _('Image files'))] |
|
689 |
filetypes_cfg = get_cfg('filetypes', {}) |
|
690 |
if filetypes_cfg: |
|
691 |
for file_type in filetypes_cfg.values(): |
|
692 |
file_types.append(( |
|
693 |
','.join(file_type['mimetypes']), file_type['label'])) |
|
694 |
if self.file_type: |
|
695 |
known_file_types = [x[0] for x in file_types] |
|
696 |
for file_type in self.file_type: |
|
697 |
if not file_type in known_file_types: |
|
698 |
file_types.append((file_type, file_type)) |
|
699 |
form.add(CheckboxesWidget, 'file_type', title=_('File type suggestion'), |
|
700 |
value=self.file_type, elements=file_types, inline=True, |
|
701 |
advanced=not(self.file_type)) |
|
694 |
document_types = self.get_document_types() |
|
695 |
cur_dt = self.document_type |
|
696 |
# SingleSelectWidget compare the value and not the keys, so if we want |
|
697 |
# the current value not to be hidden, we must reset it with the corresponding |
|
698 |
# value from settings based on the 'id' |
|
699 |
document_type_id = self.document_type.get('id') |
|
700 |
if document_type_id in document_types \ |
|
701 |
and self.document_type != document_types[document_type_id]: |
|
702 |
self.document_type = document_types[document_type_id] |
|
703 |
options = [(None, '---', {})] |
|
704 |
options += [(doc_type, doc_type['label'], key) for key, doc_type in document_types.iteritems()] |
|
705 |
form.add(SingleSelectWidget, 'document_type', title=_('File type suggestion'), |
|
706 |
value=self.document_type, options=options, |
|
707 |
advanced=not(self.document_type)) |
|
702 | 708 |
form.add(FileSizeWidget, 'max_file_size', title=('Max file size'), |
703 | 709 |
value=self.max_file_size, |
704 | 710 |
advanced=not(self.max_file_size)) |
705 | 711 | |
706 | 712 |
def get_admin_attributes(self): |
707 |
return WidgetField.get_admin_attributes(self) + ['file_type',
|
|
708 |
'max_file_size'] |
|
713 |
return WidgetField.get_admin_attributes(self) + ['document_type',
|
|
714 |
'max_file_size']
|
|
709 | 715 | |
710 | 716 |
def get_view_value(self, value): |
711 | 717 |
return htmltext('<a download="%s" href="[download]?f=%s">%s</a>') % ( |
... | ... | |
732 | 738 |
if value and hasattr(value, 'token'): |
733 | 739 |
get_request().form[self.field_key + '$token'] = value.token |
734 | 740 | |
741 |
def get_document_types(self): |
|
742 |
document_types = { |
|
743 |
'_audio': { |
|
744 |
'label': _('Sound files'), |
|
745 |
'mimetypes': ['audio/*'], |
|
746 |
}, |
|
747 |
'_video': { |
|
748 |
'label': _('Video files'), |
|
749 |
'mimetypes': ['video/*'], |
|
750 |
}, |
|
751 |
'_image': { |
|
752 |
'label': _('Image files'), |
|
753 |
'mimetypes': ['image/*'], |
|
754 |
} |
|
755 |
} |
|
756 |
# Local document types |
|
757 |
document_types.update(get_cfg('filetypes', {})) |
|
758 |
# Remote documents types |
|
759 |
document_types.update(file_validation.get_document_types()) |
|
760 |
for key, document_type in document_types.iteritems(): |
|
761 |
document_type['id'] = key |
|
762 |
# add current file type if it does not exist anymore in the settings |
|
763 |
cur_dt = self.document_type |
|
764 |
if cur_dt and cur_dt['id'] not in document_types: |
|
765 |
document_types[cur_dt['id']] = cur_dt |
|
766 |
return document_types |
|
767 | ||
768 |
def migrate(self): |
|
769 |
if 'file_type' in self.__dict__: |
|
770 |
self.document_type = {} |
|
771 |
if self.__dict__['file_type']: |
|
772 |
file_type = self.__dict__['file_type'] |
|
773 |
document_types = self.get_document_types() |
|
774 |
for key, value in document_types.iteritems(): |
|
775 |
if self.file_type == value.get('mimetypes'): |
|
776 |
self.document_type = value.copy() |
|
777 |
self.document_type['id'] = key |
|
778 |
else: |
|
779 |
# self.file_type is a combination of file type, we create a |
|
780 |
# virtual one from them |
|
781 |
self.document_type = { |
|
782 |
'id': '_legacy', |
|
783 |
'label': ','.join(file_type), |
|
784 |
'mimetypes': file_type, |
|
785 |
} |
|
786 |
del self.__dict__['file_type'] |
|
787 |
return True |
|
788 |
return False |
|
789 | ||
790 |
def export_to_xml(self, charset, include_id=False): |
|
791 |
# convert some sub-fields to strings as export_to_xml() only supports |
|
792 |
# dictionnaries with strings values |
|
793 |
if self.document_type and self.document_type.get('mimetypes'): |
|
794 |
old_value = self.document_type['mimetypes'] |
|
795 |
self.document_type['mimetypes'] = '|'.join(self.document_type['mimetypes']) |
|
796 |
result = super(FileField, self).export_to_xml(charset, include_id=include_id) |
|
797 |
if self.document_type and self.document_type.get('mimetypes'): |
|
798 |
self.document_type['mimetypes'] = old_value |
|
799 |
return result |
|
800 | ||
801 |
def init_with_xml(self, element, charset, include_id=False): |
|
802 |
super(FileField, self).init_with_xml(element, charset, include_id=include_id) |
|
803 |
# translate fields flattened to strings |
|
804 |
if self.document_type and self.document_type.get('mimetypes'): |
|
805 |
self.document_type['mimetypes'] = self.document_type['mimetypes'].split('|') |
|
806 |
if self.document_type and self.document_type.get('fargo'): |
|
807 |
self.document_type['fargo'] = self.document_type['fargo'] == 'True' |
|
808 | ||
809 | ||
735 | 810 |
register_field_class(FileField) |
736 | 811 | |
737 | 812 |
wcs/file_validation.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2010 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
import json |
|
18 |
import urlparse |
|
19 |
import hashlib |
|
20 |
import urllib |
|
21 | ||
22 |
from qommon.misc import http_get_page, json_loads |
|
23 |
from quixote import get_publisher, get_response |
|
24 |
from quixote.html import htmltext |
|
25 | ||
26 | ||
27 |
def has_file_validation(): |
|
28 |
return get_publisher().get_site_option('fargo_url') is not None |
|
29 | ||
30 |
def fargo_get(path): |
|
31 |
fargo_url = get_publisher().get_site_option('fargo_url') |
|
32 |
url = urlparse.urljoin(fargo_url, path) |
|
33 |
response, status, data, auth_header = http_get_page(url) |
|
34 |
if status == 200: |
|
35 |
return json_loads(data) |
|
36 |
return None |
|
37 | ||
38 |
def sha256_of_upload(upload): |
|
39 |
return hashlib.sha256(upload.get_content()).hexdigest() |
|
40 | ||
41 |
def get_document_types(): |
|
42 |
if not has_file_validation(): |
|
43 |
return {} |
|
44 |
response = fargo_get('/document-types/') |
|
45 |
publisher = get_publisher() |
|
46 |
if response.get('err') == 0: |
|
47 |
result = {} |
|
48 |
for schema in response['data']: |
|
49 |
d = { |
|
50 |
'id': schema['name'], |
|
51 |
'label': schema['label'], |
|
52 |
'fargo': True, |
|
53 |
} |
|
54 |
if 'mimetypes' in schema: |
|
55 |
d['mimetypes'] = shema['mimetypes'] |
|
56 |
result[d['id']] = d |
|
57 | ||
58 |
return result |
|
59 |
return {} |
|
60 | ||
61 |
def validation_path(filled, field, upload): |
|
62 |
user = filled.get_user() |
|
63 |
if not user: |
|
64 |
return None |
|
65 |
if not user.name_identifiers: |
|
66 |
return None |
|
67 |
if not field.document_type or not field.document_type.get('fargo'): |
|
68 |
return None |
|
69 |
name_id = user.name_identifiers[0] |
|
70 |
sha_256 = sha256_of_upload(upload) |
|
71 |
document_type = field.document_type['id'] |
|
72 |
path = '%s/%s/%s/' % ( |
|
73 |
urllib.quote(name_id), |
|
74 |
urllib.quote(sha_256), |
|
75 |
urllib.quote(document_type), |
|
76 |
) |
|
77 |
return path |
|
78 | ||
79 |
def validate_upload(filled, field, upload): |
|
80 |
'''Check validation of the uploaded file with Fargo''' |
|
81 |
path = validation_path(filled, field, upload) |
|
82 |
if not path: |
|
83 |
return None |
|
84 |
response = fargo_get('metadata/' + path) |
|
85 |
if response is None: |
|
86 |
return None |
|
87 |
if response['err'] == 1: |
|
88 |
return False |
|
89 |
return response['data'] |
|
90 | ||
91 |
def get_document_type_label(document_type): |
|
92 |
return get_document_types().get(document_type, {}).get('label') |
|
93 | ||
94 |
def validation_link(filled, field, upload): |
|
95 |
'''Compute link to Fargo to validate the given document''' |
|
96 |
path = validation_path(filled, field, upload) |
|
97 |
if not path: |
|
98 |
return '' |
|
99 |
get_response().add_css_include('../js/smoothness/jquery-ui-1.10.0.custom.min.css') |
|
100 |
get_response().add_javascript(['jquery-ui.js', 'jquery.js', 'fargo.js']) |
|
101 |
label = get_document_type_label(field.document_type['id']) |
|
102 |
fargo_url = get_publisher().get_site_option('fargo_url') |
|
103 |
url = urlparse.urljoin(fargo_url, 'validation/' + path) |
|
104 |
next_url = get_publisher().get_frontoffice_url() + '/reload-top' |
|
105 |
url += '?next=%s' % urllib.quote(next_url) |
|
106 |
title = _('Validate as a %s') % label |
|
107 |
return htmltext('<a data-title="%(title)s" data-width="800" ' |
|
108 |
'data-height="500" href="%(url)s">%(title)s</a>') % { |
|
109 |
'title': title, |
|
110 |
'url': url, |
|
111 |
} |
wcs/forms/common.py | ||
---|---|---|
15 | 15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import sys |
18 |
import hashlib |
|
19 |
import urlparse |
|
18 | 20 | |
19 | 21 |
from quixote import get_publisher, get_request, get_response, get_session, redirect |
20 | 22 |
from quixote.directory import Directory |
21 | 23 |
from quixote.html import TemplateIO, htmltext |
22 | 24 | |
23 |
from wcs.fields import WidgetField |
|
25 |
from wcs.fields import WidgetField, FileField |
|
26 |
from wcs import file_validation |
|
24 | 27 | |
25 | 28 |
from qommon import template |
26 | 29 |
from qommon import get_logger |
... | ... | |
395 | 398 |
continue |
396 | 399 | |
397 | 400 |
r += htmltext('<div class="field"><span class="label">%s</span> ') % f.label |
398 |
r += htmltext('<div class="value">') |
|
399 |
s = f.get_view_value(value) |
|
400 |
s = s.replace(str('[download]'), str('%sdownload' % form_url)) |
|
401 |
r += s |
|
402 |
r += htmltext('</div></div>') |
|
403 | ||
401 |
if isinstance(f, FileField): |
|
402 |
r += htmltext(self.display_file_field(form_url, f, value)) |
|
403 |
else: # normal display |
|
404 |
r += htmltext('<div class="value">') |
|
405 |
s = f.get_view_value(value) |
|
406 |
s = s.replace(str('[download]'), str('%sdownload' % form_url)) |
|
407 |
r += s |
|
408 |
r += htmltext('</div>') |
|
409 |
r += htmltext('</div>') |
|
404 | 410 | |
405 | 411 |
if on_page: |
406 | 412 |
r += htmltext('</div>') |
... | ... | |
529 | 535 |
else: |
530 | 536 |
return redirect('files/%s/' % fn) |
531 | 537 | |
538 |
def display_file_field(self, form_url, field, value): |
|
539 |
r = TemplateIO(html=True) |
|
540 |
status = None |
|
541 |
if file_validation.has_file_validation(): |
|
542 |
status = file_validation.validate_upload(self.filled, field, value) |
|
543 |
if status is False: |
|
544 |
extra_class = ' invalid' |
|
545 |
elif status is None: |
|
546 |
extra_class = '' |
|
547 |
else: |
|
548 |
extra_class = ' valid' |
|
549 |
r += htmltext('<div class="value%s">' % extra_class) |
|
550 |
else: |
|
551 |
r += htmltext('<div class="value">') |
|
552 |
s = field.get_view_value(value) |
|
553 |
s = s.replace(str('[download]'), str('%sdownload' % form_url)) |
|
554 |
r += s |
|
555 |
if status is not None and get_request().is_in_backoffice(): |
|
556 |
r += htmltext('<div class="file-validation">') |
|
557 |
if status: |
|
558 |
r += htmltext(_('<p>%s validated by %s on %s</p>')) % ( |
|
559 |
status['label'], status['creator'], status['created']) |
|
560 |
r += htmltext('<ul>') |
|
561 |
for meta in status['metadata']: |
|
562 |
r += htmltext(_('<li>%(label)s: %(value)s</li>')) % { |
|
563 |
'label': meta['label'], |
|
564 |
'value': meta['value'] |
|
565 |
} |
|
566 |
r += htmltext('</ul>') |
|
567 |
r += htmltext('<p>%s</p>') % (_('Valid from %(start)s to %(end)s') % { |
|
568 |
'start': status['start'], |
|
569 |
'end': status['end'], |
|
570 |
}) |
|
571 |
else: |
|
572 |
r += file_validation.validation_link(self.filled, field, value) |
|
573 |
r += htmltext('</div>') |
|
574 |
r += htmltext('</div>') |
|
575 |
return str(r) |
|
576 | ||
532 | 577 |
def _q_lookup(self, component): |
533 | 578 |
if component == 'files': |
534 | 579 |
self.check_receiver() |
wcs/qommon/static/js/fargo.js | ||
---|---|---|
1 | ||
2 |
$(function() { |
|
3 |
var iframe = $('<iframe frameborder="0" marginwidth="0" marginheight="0" allowfullscreen></iframe>'); |
|
4 |
var dialog = $("<div></div>").append(iframe).appendTo("body").dialog({ |
|
5 |
autoOpen: false, |
|
6 |
modal: true, |
|
7 |
resizable: false, |
|
8 |
width: "auto", |
|
9 |
height: "auto", |
|
10 |
close: function () { |
|
11 |
iframe.attr("src", ""); |
|
12 |
} |
|
13 |
}); |
|
14 |
$('.file-validation a').click(function (e) { |
|
15 |
e.preventDefault(); |
|
16 |
var src = $(e.target).attr('href'); |
|
17 |
var title = $(e.target).data("title"); |
|
18 |
var width = $(e.target).data("width"); |
|
19 |
var height = $(e.target).data("height"); |
|
20 |
iframe.attr({ |
|
21 |
width: parseInt(width), |
|
22 |
height: parseInt(height), |
|
23 |
src: src |
|
24 |
}); |
|
25 |
dialog.dialog("option", "title", title); |
|
26 |
dialog.dialog("open"); |
|
27 |
}); |
|
28 |
$('p.use-file-from-fargo span').click(function(e) { |
|
29 |
e.preventDefault(); |
|
30 |
var base_widget = $(this).parents('.file-upload-widget'); |
|
31 |
document.fargo_set_token = function (token, title) { |
|
32 |
if (token) { |
|
33 |
$(base_widget).find('.filename').text(title); |
|
34 |
$(base_widget).find('.fileinfo').show(); |
|
35 |
$(base_widget).find('input[type=hidden]').val(token); |
|
36 |
$(base_widget).find('input[type=file]').hide(); |
|
37 |
} |
|
38 |
document.fargo_close_dialog(); |
|
39 |
} |
|
40 |
document.fargo_close_dialog = function () { |
|
41 |
document.fargo_set_token = undefined; |
|
42 |
dialog.dialog('close'); |
|
43 |
} |
|
44 |
var src = $(this).data('src'); |
|
45 |
var title = $(this).data("title"); |
|
46 |
var width = $(this).data("width"); |
|
47 |
var height = $(this).data("height"); |
|
48 |
iframe.attr({ |
|
49 |
width: parseInt(width), |
|
50 |
height: parseInt(height), |
|
51 |
src: src |
|
52 |
}); |
|
53 |
dialog.dialog("option", "title", title); |
|
54 |
dialog.dialog("open"); |
|
55 |
}); |
|
56 |
}); |
wcs/root.py | ||
---|---|---|
192 | 192 |
_q_exports = ['admin', 'backoffice', 'forms', 'login', 'logout', 'saml', |
193 | 193 |
'ident', 'register', 'afterjobs', 'themes', 'myspace', 'user', 'roles', |
194 | 194 |
'pages', ('tmp-upload', 'tmp_upload'), 'api', '__version__', |
195 |
'tryauth', 'auth', 'preview'] |
|
195 |
'tryauth', 'auth', 'preview', ('reload-top', 'reload_top')]
|
|
196 | 196 | |
197 | 197 |
api = ApiDirectory() |
198 | 198 |
themes = template.ThemesDirectory() |
... | ... | |
308 | 308 |
# or a form ? |
309 | 309 |
return forms.root.RootDirectory()._q_lookup(component) |
310 | 310 | |
311 |
def reload_top(self): |
|
312 |
get_response().filter = {} |
|
313 |
return htmltext('<html><body><script>window.top.document.location.reload();</script></body></html>') |
|
314 | ||
311 | 315 |
admin = None |
312 | 316 |
backoffice = None |
313 | 317 | |
314 |
- |