0001-general-add-geolocation-to-formdata-10581.patch
tests/test_formdef_import.py | ||
---|---|---|
340 | 340 |
role.remove_self() |
341 | 341 |
fd2 = FormDef.import_from_xml_tree(xml_export, include_id=True) |
342 | 342 |
assert fd2.workflow_roles.get('_receiver') is None |
343 | ||
344 |
def test_geolocations(): |
|
345 |
formdef = FormDef() |
|
346 |
formdef.name = 'foo' |
|
347 |
formdef.fields = [] |
|
348 |
formdef.geolocations = {'base': 'Base'} |
|
349 |
fd2 = assert_xml_import_export_works(formdef, include_id=True) |
|
350 |
assert fd2.geolocations == formdef.geolocations |
|
351 |
fd3 = assert_json_import_export_works(formdef) |
|
352 |
assert fd3.geolocations == formdef.geolocations |
tests/test_sql.py | ||
---|---|---|
178 | 178 |
check_sql_field('6', ['apricot', 'pear']) |
179 | 179 | |
180 | 180 |
@postgresql |
181 |
def test_sql_geoloc(): |
|
182 |
test_formdef = FormDef() |
|
183 |
test_formdef.name = 'geoloc' |
|
184 |
test_formdef.fields = [] |
|
185 |
test_formdef.geolocations = {'base': 'Plop'} |
|
186 |
test_formdef.store() |
|
187 |
data_class = test_formdef.data_class(mode='sql') |
|
188 |
formdata = data_class() |
|
189 |
formdata.data = {} |
|
190 |
formdata.geolocations = {'base': {'lat': 12, 'lon': 21}} |
|
191 |
formdata.store() |
|
192 | ||
193 |
formdata2 = data_class.get(formdata.id) |
|
194 |
assert formdata2.geolocations == formdata.geolocations |
|
195 | ||
196 |
formdata.geolocations = {} |
|
197 |
formdata.store() |
|
198 |
formdata2 = data_class.get(formdata.id) |
|
199 |
assert formdata2.geolocations == formdata.geolocations |
|
200 | ||
201 |
@postgresql |
|
202 |
def test_sql_multi_geoloc(): |
|
203 |
test_formdef = FormDef() |
|
204 |
test_formdef.name = 'geoloc' |
|
205 |
test_formdef.fields = [] |
|
206 |
test_formdef.geolocations = {'base': 'Plop'} |
|
207 |
test_formdef.store() |
|
208 |
data_class = test_formdef.data_class(mode='sql') |
|
209 |
formdata = data_class() |
|
210 |
formdata.data = {} |
|
211 |
formdata.geolocations = {'base': {'lat': 12, 'lon': 21}} |
|
212 |
formdata.store() |
|
213 | ||
214 |
formdata2 = data_class.get(formdata.id) |
|
215 |
assert formdata2.geolocations == formdata.geolocations |
|
216 | ||
217 |
test_formdef.geolocations = {'base': 'Plop', '2nd': 'XXX'} |
|
218 |
test_formdef.store() |
|
219 |
formdata.geolocations = {'base': {'lat': 12, 'lon': 21}, '2nd': {'lat': -34, 'lon': -12}} |
|
220 |
formdata.store() |
|
221 |
formdata2 = data_class.get(formdata.id) |
|
222 |
assert formdata2.geolocations == formdata.geolocations |
|
223 | ||
224 |
test_formdef.geolocations = {'base': 'Plop'} |
|
225 |
test_formdef.store() |
|
226 |
formdata2 = data_class.get(formdata.id) |
|
227 |
assert formdata2.geolocations == {'base': {'lat': 12, 'lon': 21}} |
|
228 | ||
229 |
@postgresql |
|
181 | 230 |
def test_sql_change(): |
182 | 231 |
data_class = formdef.data_class(mode='sql') |
183 | 232 |
formdata = data_class() |
wcs/formdata.py | ||
---|---|---|
175 | 175 | |
176 | 176 |
workflow_data = None |
177 | 177 |
workflow_roles = None |
178 |
geolocations = None |
|
178 | 179 | |
179 | 180 |
_formdef = None |
180 | 181 |
def get_formdef(self): |
... | ... | |
505 | 506 |
except KeyError: |
506 | 507 |
pass |
507 | 508 | |
509 |
if self.geolocations: |
|
510 |
for k, v in self.geolocations.items(): |
|
511 |
d['form_geoloc_%s' % k] = v |
|
512 | ||
508 | 513 |
if self.evolution and self.evolution[-1].comment: |
509 | 514 |
d['form_comment'] = self.evolution[-1].comment |
510 | 515 |
else: |
... | ... | |
548 | 553 |
d['form_url'], formvar, fieldvar, |
549 | 554 |
self.workflow_data['%s_var_%s' % (formvar, fieldvar)]) |
550 | 555 | |
556 |
if self.geolocations: |
|
557 |
for k, v in self.geolocations.items(): |
|
558 |
d['form_geoloc_%s_lat' % k] = v.get('lat') |
|
559 |
d['form_geoloc_%s_lon' % k] = v.get('lon') |
|
560 | ||
551 | 561 |
d = copy.deepcopy(d) |
552 | 562 |
flatten_dict(d) |
553 | 563 |
wcs/formdef.py | ||
---|---|---|
88 | 88 |
skip_from_360_view = False |
89 | 89 |
private_status_and_history = False |
90 | 90 | |
91 |
geolocations = None |
|
92 | ||
91 | 93 |
last_modification_time = None |
92 | 94 |
last_modification_user_id = None |
93 | 95 | |
... | ... | |
549 | 551 |
for field in self.fields: |
550 | 552 |
root['fields'].append(field.export_to_json(include_id=include_id)) |
551 | 553 | |
554 |
if self.geolocations: |
|
555 |
root['geolocations'] = self.geolocations.copy() |
|
556 | ||
552 | 557 |
if self.workflow_options: |
553 | 558 |
root['options'] = self.workflow_options |
554 | 559 | |
... | ... | |
632 | 637 |
if value.get('options'): |
633 | 638 |
formdef.workflow_options = value.get('options') |
634 | 639 | |
640 |
if value.get('geolocations'): |
|
641 |
formdef.geolocations = value.get('geolocations') |
|
642 | ||
635 | 643 |
return formdef |
636 | 644 | |
637 | 645 |
def export_to_xml(self, include_id=False): |
... | ... | |
711 | 719 |
else: |
712 | 720 |
pass # TODO: extend support to other types |
713 | 721 | |
722 |
geolocations = ET.SubElement(root, 'geolocations') |
|
723 |
for geoloc_key, geoloc_label in (self.geolocations or {}).items(): |
|
724 |
element = ET.SubElement(geolocations, 'geolocation') |
|
725 |
element.attrib['key'] = geoloc_key |
|
726 |
element.text = unicode(geoloc_label, charset) |
|
727 | ||
714 | 728 |
return root |
715 | 729 | |
716 | 730 |
@classmethod |
... | ... | |
861 | 875 | |
862 | 876 |
formdef.workflow_roles[role_key] = role_id |
863 | 877 | |
878 |
if tree.find('geolocations') is not None: |
|
879 |
geolocations_node = tree.find('geolocations') |
|
880 |
formdef.geolocations = {} |
|
881 |
for child in geolocations_node.getchildren(): |
|
882 |
geoloc_key = child.attrib['key'] |
|
883 |
geoloc_value = child.text.encode(charset) |
|
884 |
formdef.geolocations[geoloc_key] = geoloc_value |
|
885 | ||
864 | 886 |
return formdef |
865 | 887 | |
866 | 888 |
def get_detailed_email_form(self, formdata, url): |
wcs/sql.py | ||
---|---|---|
17 | 17 |
import psycopg2 |
18 | 18 |
import datetime |
19 | 19 |
import time |
20 |
import re |
|
20 | 21 |
import cPickle |
21 | 22 | |
22 | 23 |
from quixote import get_publisher |
... | ... | |
399 | 400 |
cur.execute('''ALTER TABLE %s ADD COLUMN %s bytea''' % ( |
400 | 401 |
table_name, 'f%s_structured' % field.id)) |
401 | 402 | |
403 |
for field in (formdef.geolocations or {}).keys(): |
|
404 |
column_name = 'geoloc_%s' % field |
|
405 |
needed_fields.add(column_name) |
|
406 |
if column_name not in existing_fields: |
|
407 |
cur.execute('ALTER TABLE %s ADD COLUMN %s %s''' % ( |
|
408 |
table_name, column_name, 'POINT')) |
|
409 | ||
402 | 410 |
# delete obsolete fields |
403 | 411 |
for field in (existing_fields - needed_fields): |
404 | 412 |
cur.execute('''ALTER TABLE %s DROP COLUMN %s CASCADE''' % (table_name, field)) |
... | ... | |
922 | 930 |
def _row2obdata(cls, row, formdef): |
923 | 931 |
obdata = {} |
924 | 932 |
i = len(cls._table_static_fields) |
933 |
if formdef.geolocations: |
|
934 |
i += len(formdef.geolocations.keys()) |
|
925 | 935 |
for field in formdef.fields: |
926 | 936 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
927 | 937 |
if sql_type is None: |
... | ... | |
958 | 968 |
if obdata['%s_structured' % field.id] is None: |
959 | 969 |
del obdata['%s_structured' % field.id] |
960 | 970 |
i += 1 |
971 | ||
961 | 972 |
return obdata |
962 | 973 | |
963 | 974 |
@classmethod |
... | ... | |
1128 | 1139 |
else: |
1129 | 1140 |
sql_dict['submission_context'] = None |
1130 | 1141 | |
1142 |
for field in (self._formdef.geolocations or {}).keys(): |
|
1143 |
value = (self.geolocations or {}).get(field) |
|
1144 |
if value: |
|
1145 |
value = '(%.6f, %.6f)' % (value.get('lon'), value.get('lat')) |
|
1146 |
sql_dict['geoloc_%s' % field] = value |
|
1147 | ||
1131 | 1148 |
sql_dict['concerned_roles_array'] = [str(x) for x in self.concerned_roles if x] |
1132 | 1149 |
sql_dict['actions_roles_array'] = [str(x) for x in self.actions_roles if x] |
1133 | 1150 | |
... | ... | |
1242 | 1259 |
o.workflow_roles = cPickle.loads(str(o.workflow_roles)) |
1243 | 1260 |
if o.submission_context: |
1244 | 1261 |
o.submission_context = cPickle.loads(str(o.submission_context)) |
1262 | ||
1263 |
o.geolocations = {} |
|
1264 |
for i, field in enumerate((cls._formdef.geolocations or {}).keys()): |
|
1265 |
value = row[len(cls._table_static_fields)+i] |
|
1266 |
if not value: |
|
1267 |
continue |
|
1268 |
m = re.match(r"\(([^)]+),([^)]+)\)", value) |
|
1269 |
o.geolocations[field] = {'lon': float(m.group(1)), |
|
1270 |
'lat': float(m.group(2))} |
|
1271 | ||
1245 | 1272 |
o.data = cls._row2obdata(row, cls._formdef) |
1246 | 1273 |
return o |
1247 | 1274 | |
1248 | 1275 |
@classmethod |
1249 | 1276 |
def get_data_fields(cls): |
1250 |
data_fields = [] |
|
1277 |
data_fields = ['geoloc_%s' % x for x in (cls._formdef.geolocations or {}).keys()]
|
|
1251 | 1278 |
for field in cls._formdef.fields: |
1252 | 1279 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
1253 | 1280 |
if sql_type is None: |
... | ... | |
1274 | 1301 |
raise KeyError() |
1275 | 1302 |
conn, cur = get_connection_and_cursor() |
1276 | 1303 | |
1304 |
fields = cls.get_data_fields() |
|
1305 | ||
1277 | 1306 |
potential_comma = ', ' |
1278 |
if not cls.get_data_fields():
|
|
1307 |
if not fields:
|
|
1279 | 1308 |
potential_comma = '' |
1280 | 1309 | |
1281 | 1310 |
sql_statement = '''SELECT %s |
... | ... | |
1285 | 1314 |
WHERE id = %%(id)s''' % ( |
1286 | 1315 |
', '.join([x[0] for x in cls._table_static_fields]), |
1287 | 1316 |
potential_comma, |
1288 |
', '.join(cls.get_data_fields()),
|
|
1317 |
', '.join(fields),
|
|
1289 | 1318 |
cls._table_name) |
1290 | 1319 |
cur.execute(sql_statement, {'id': str(id)}) |
1291 | 1320 |
row = cur.fetchone() |
... | ... | |
1814 | 1843 |
return result |
1815 | 1844 | |
1816 | 1845 | |
1817 |
SQL_LEVEL = 14
|
|
1846 |
SQL_LEVEL = 15
|
|
1818 | 1847 | |
1819 | 1848 |
def migrate_global_views(conn, cur): |
1820 | 1849 |
cur.execute('''SELECT COUNT(*) FROM information_schema.tables |
... | ... | |
1848 | 1877 |
raise RuntimeError() |
1849 | 1878 |
if sql_level < 1: # 1: introduction of tracking_code table |
1850 | 1879 |
do_tracking_code_table() |
1851 |
if sql_level < 14:
|
|
1880 |
if sql_level < 15:
|
|
1852 | 1881 |
# 2: introduction of formdef_id in views |
1853 | 1882 |
# 5: add concerned_roles_array, is_at_endpoint and fts to views |
1854 | 1883 |
# 7: add backoffice_submission to tables |
... | ... | |
1858 | 1887 |
# 11: add formdef_name and user_name to views |
1859 | 1888 |
# 13: add backoffice_submission to views |
1860 | 1889 |
# 14: add criticality_level to tables & views |
1890 |
# 15: add geolocation to formdata |
|
1861 | 1891 |
migrate_views(conn, cur) |
1862 | 1892 |
if sql_level < 12: |
1863 | 1893 |
# 3: introduction of _structured for user fields |
1864 |
- |