Mercurial > hg > ChinaGisRestApi
annotate RestDbGisApi.py @ 278:4ade9b80b563 default tip
more cleanup.
descriptions work better now.
author | casties |
---|---|
date | Fri, 24 Feb 2012 16:41:30 +0100 |
parents | 55bc9972fb1b |
children |
rev | line source |
---|---|
43 | 1 ''' |
2 Created on 2.9.2010 | |
3 | |
4 @author: casties, fknauft | |
5 ''' | |
6 | |
7 from OFS.Folder import Folder | |
8 from Products.PageTemplates.PageTemplateFile import PageTemplateFile | |
9 from Products.ZSQLExtend import ZSQLExtend | |
10 import logging | |
11 import re | |
12 import time | |
61 | 13 import datetime |
247 | 14 import urlFunctions |
43 | 15 |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
16 from Products.ZDBInterface.WritableRestDbInterface import * |
43 | 17 |
18 | |
55 | 19 def kmlEncode(s): |
20 """returns string encoded for displaying in KML attribute""" | |
21 res = s.replace("'","__Apostroph__") | |
22 res = res.replace('"','__DoubleApostroph__') | |
23 res = res.replace(';','__$$__') | |
24 res = res.replace('&','&') | |
25 return res | |
26 | |
27 | |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
28 class RestDbGisApi(WritableRestDbInterface): |
43 | 29 """Object for RESTful GIS database queries |
30 path schema: /db/{schema}/{table}/ | |
31 omitting table gives a list of schemas | |
32 omitting table and schema gives a list of schemas | |
33 """ | |
34 | |
35 meta_type="RESTgis" | |
36 | |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
37 # data templates |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
38 GIS_schema_table = PageTemplateFile('zpt/GIS_schema_table', globals()) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
39 KML_schema_table = PageTemplateFile('zpt/KML_schema_table', globals()) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
40 HTML_schema_usertables = PageTemplateFile('zpt/HTML_schema_usertables', globals()) |
55 | 41 |
44 | 42 # and scripts |
254
901c1f745d13
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
252
diff
changeset
|
43 def KML_URL_schema_table(self,schema,table, useTimestamp=True, args=None): |
44 | 44 """KML_URL table function""" |
45 self.REQUEST.RESPONSE.setHeader("Content-Type", "text/plain") | |
46 id = self.REQUEST.get('id',[]) | |
47 doc = self.REQUEST.get('doc',None) | |
245 | 48 # return self.getLiveKmlUrl(schema=schema,table=table, useTimestamp=useTimestamp) |
49 return self.getLiveKmlUrl(schema=schema,table=table, useTimestamp=False) | |
43 | 50 |
61 | 51 # |
52 # database methods | |
53 # | |
70 | 54 toSqlTypeMap = { |
55 "text": "text", | |
56 "number": "numeric", | |
57 "id": "text", | |
58 "gis_id": "text", | |
59 "coord_lat": "numeric", | |
252
efd2469d1722
geometry-column of tables will be displayed as string
fknauft
parents:
250
diff
changeset
|
60 "coord_lon": "numeric", |
263 | 61 "the_geom": "the_geom", |
62 "from_year":"text", | |
63 "until_year":"text" | |
70 | 64 } |
65 | |
60 | 66 def getTableOwner(self,schema,table): |
67 """returns the owner of the table""" | |
61 | 68 # what do we do with the schema? |
69 sql = 'select table_owner from public.gis_table_meta where table_name = %s' | |
70 res = self.executeSQL(sql,(table,)) | |
71 if len(res['rows']) > 0: | |
72 return res['rows'][0][0] | |
60 | 73 return None |
74 | |
75 def isAllowed(self,action,schema,table,user=None,owner=None): | |
43 | 76 """returns if the requested action on the table is allowed""" |
77 if user is None: | |
78 user = self.REQUEST.get('AUTHENTICATED_USER',None) | |
60 | 79 logging.debug("isAllowed action=%s schema=%s table=%s user=%s"%(action,schema,table,user)) |
80 if action == "create": | |
81 if user is not None and str(user) != 'Anonymous User': | |
82 # any authenticated user can create | |
83 return True | |
84 else: | |
85 return False | |
86 | |
87 if action == "update": | |
88 if owner is None: | |
89 owner = self.getTableOwner(schema,table) | |
61 | 90 logging.debug("isAllowed user=%s owner=%s"%(user,owner)) |
60 | 91 if user is not None and str(user) == str(owner): |
92 # update only your own table | |
93 return True | |
94 else: | |
95 return False | |
96 | |
62 | 97 # anything else is allowed |
43 | 98 return True |
99 | |
61 | 100 def setTableMetaTypes(self,schema,table,fields,user=None): |
43 | 101 """sets the GIS meta information for table""" |
61 | 102 if user is None: |
103 user = self.REQUEST.get('AUTHENTICATED_USER',None) | |
104 | |
105 logging.debug("settablemetatypes schema=%s, table=%s, fields=%s user=%s"%(schema,table,fields,user)) | |
43 | 106 |
61 | 107 today = datetime.date.today().isoformat() |
108 | |
109 res = self.executeSQL('select * from public.gis_table_meta where table_name = %s', (table,)) | |
43 | 110 if len(res['rows']) > 0: |
111 # meta record exists | |
61 | 112 sql = 'update public.gis_table_meta set table_owner=%s, table_modified=%s where table_name=%s' |
113 self.executeSQL(sql, (str(user),today,table), hasResult=False) | |
43 | 114 else: |
115 # new meta record | |
61 | 116 sql = 'insert into public.gis_table_meta (table_name,table_owner,table_created) values (%s,%s,%s)' |
117 self.executeSQL(sql, (table,str(user),today), hasResult=False) | |
118 | |
119 # update row info | |
120 sql = 'delete from public.gis_table_meta_rows where table_name=%s' | |
121 self.executeSQL(sql,(table,),hasResult=False) | |
122 sql = 'insert into public.gis_table_meta_rows (table_name,field_name,gis_type) values (%s,%s,%s)' | |
123 for f in fields: | |
124 t = f['type'] | |
125 fn = f['name'] | |
126 self.executeSQL(sql, (table,fn,t), hasResult=False) | |
43 | 127 |
128 | |
61 | 129 def getListOfUserTables(self,schema='public',username='guest'): |
130 """return list of tables""" | |
131 logging.debug("getlistofusertables") | |
132 # get list of db tables | |
100 | 133 # qstr = """SELECT t.table_name FROM information_schema.tables t, public.gis_table_meta m WHERE t.table_type = 'BASE TABLE' |
134 # AND t.table_schema = %s AND t.table_name = m.table_name ORDER BY 1""" | |
135 qstr = """SELECT t.table_name FROM information_schema.tables t, public.gis_table_meta m | |
136 WHERE t.table_schema = %s AND t.table_name = m.table_name ORDER BY 1""" | |
43 | 137 |
61 | 138 data=self.executeSQL(qstr,(schema,)) |
139 return data | |
140 | |
43 | 141 |
142 def createEmptyTable(self,schema,table,fields): | |
143 """create a table with the given fields | |
144 returns list of created fields""" | |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
145 sqlFields = WritableRestDbInterface.createEmptyTable(self,schema,table,fields) |
61 | 146 if sqlFields is not None: |
43 | 147 self.setTableMetaTypes(schema,table,sqlFields) |
61 | 148 |
149 return sqlFields | |
43 | 150 |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
151 # TODO: move this |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
152 def getAttributeNames(self,schema='public',table=None): |
275 | 153 return self.executeSQL("SELECT attname FROM pg_attribute, pg_class WHERE pg_class.oid = attrelid AND attnum>0 AND relname = %s", (table)) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
154 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
155 # TODO: move this |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
156 def getAttributeTypes(self,schema='public',table=None): |
275 | 157 return self.executeSQL("SELECT field_name, gis_type FROM public.gis_table_meta_rows WHERE table_name = %s", (table)) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
158 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
159 # TODO: move back to inherited version |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
160 def showTable(self,format='XML',schema='public',table=None,REQUEST=None,RESPONSE=None): |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
161 """returns PageTemplate with tables""" |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
162 logging.debug("showtable") |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
163 if REQUEST is None: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
164 REQUEST = self.REQUEST |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
165 queryArgs={'doc':None,'id':None} |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
166 queryArgs['doc'] = REQUEST.get('doc') |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
167 queryArgs['id'] = REQUEST.get('id') |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
168 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
169 # should be cross-site accessible |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
170 if RESPONSE is None: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
171 RESPONSE = self.REQUEST.RESPONSE |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
172 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
173 RESPONSE.setHeader('Access-Control-Allow-Origin', '*') |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
174 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
175 # everything else has its own template |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
176 pt = getattr(self.template, '%s_schema_table'%format, REQUEST) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
177 if pt is None: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
178 return "ERROR!! template %s_schema_table not found at %s"%(format, self.template ) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
179 #data = self.getTable(schema,table) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
180 return pt(schema=schema,table=table,args=queryArgs) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
181 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
182 #TODO: move to parent class |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
183 def getLiveUrl(self,schema,table,useTimestamp=True,REQUEST=None): |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
184 if REQUEST is None: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
185 REQUEST = self.REQUEST |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
186 logging.debug("getLiveUrl") |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
187 baseUrl = self.absolute_url() |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
188 timestamp = time.time() |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
189 # filter parameters in URL and add to new URL |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
190 params = [p for p in REQUEST.form.items() if p[0] not in ('format','timestamp')] |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
191 params.append(('format','KML')) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
192 if useTimestamp: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
193 # add timestamp so URL changes every time |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
194 params.append(('timestamp',timestamp)) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
195 paramstr = urllib.urlencode(params) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
196 return "%s/db/%s/%s?%s"%(baseUrl,schema,table,paramstr) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
197 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
198 |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
199 # TODO: remove changes from parent version |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
200 def getTable(self,schema='public',table=None,sortBy=1,username='guest'): |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
201 """return table data""" |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
202 logging.debug("gettable") |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
203 attrNames=self.getAttributeNames(schema,table) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
204 attrTypes=self.getAttributeTypes(schema,table) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
205 attrString="" |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
206 # try: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
207 for name in attrNames['rows']: |
275 | 208 logging.debug("name: %s"%name[0]) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
209 not_added=True |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
210 if name[0] == "the_geom": #FJK: the table column is "the_geom" |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
211 attrString=attrString+"ST_AsText("+name[0]+")," |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
212 not_added=False |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
213 break |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
214 for a_iter in attrTypes['rows']: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
215 not_added = True |
275 | 216 logging.debug("attrTypes.field_name: %s"%a_iter[0]) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
217 if a_iter[0]==name[0]: |
275 | 218 logging.debug("attrTypes.gis_type: %s"%a_iter[1]) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
219 if a_iter[1] == "the_geom": #FJK: the table column is registered in gis_table_meta_rows as type "the_geom" |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
220 attrString=attrString+"ST_AsText("+name[0]+")," |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
221 not_added=False |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
222 if not_added: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
223 if name[0].find('pg.dropped')==-1: |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
224 attrString=attrString+name[0]+"," |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
225 attrString=str(attrString).rsplit(",",1)[0] #to remove last "," |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
226 if sortBy: |
275 | 227 data = self.executeSQL('select %s from "%s"."%s" order by %%s'%(attrString,sqlName(schema),sqlName(table)),(sortBy,)) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
228 else: |
275 | 229 data = self.executeSQL('select %s from "%s"."%s"'%(attrString,sqlName(schema),sqlName(table))) |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
230 # except: |
275 | 231 # """ table does not exist """ |
274
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
232 # fields=self.get |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
233 # self.createEmptyTable(schema, table, fields) |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
234 return data |
9b7db308d2e6
refactor RestDbGisApi to use RestDbInterface from ZDbInterface Product.
casties
parents:
264
diff
changeset
|
235 |
43 | 236 |
59 | 237 def getLiveKmlUrl(self,schema,table,useTimestamp=True,REQUEST=None): |
254
901c1f745d13
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
252
diff
changeset
|
238 return self.getLiveUrl(schema,table,useTimestamp,REQUEST) |
55 | 239 |
273 | 240 def getKmlData(self, schema, table, ids=None, sortBy=1, gisIdField=None, latField=None, lonField=None, geomField="point", colorField="red_big",from_year_name='from_year',until_year_name=''): |
55 | 241 """returns data structure for KML template""" |
249 | 242 logging.debug("getKMLdata gid=%s lat=%s lon=%s sortBy=%s geom=%s color=%s"%(gisIdField,latField,lonField,sortBy,geomField,colorField)) |
148 | 243 if geomField is None: |
244 geomField="point" | |
245 if colorField is None: | |
246 colorField="red" | |
55 | 247 # Mapping a set of points from table-based SQL-query: |
275 | 248 qstr='SELECT * FROM "%s"."%s"'%(sqlName(schema),sqlName(table)) |
55 | 249 idList = None |
250 if ids is not None: | |
251 qstr += ' WHERE ' | |
255
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
252 if schema=='mpdl': |
55 | 253 qstr += 'mpdl_xmlsource_id IN (' |
254 else: | |
255 qstr += 'CAST(id AS text) IN (' | |
256 | |
257 idList = ids.split(",") | |
258 qstr += ','.join(['%s' for i in idList]) | |
259 qstr += ')' | |
260 | |
58 | 261 if sortBy: |
262 # add sort clause | |
59 | 263 if sortBy == 1: |
264 qstr += ' ORDER BY 1' | |
249 | 265 elif sortBy == 'Default': |
266 qstr += ' ORDER BY 1' | |
250
d7ceeb8ccbd7
Layer gui reordered, point order can be defined, minor edit
fknauft
parents:
249
diff
changeset
|
267 elif sortBy == 'undefined': |
d7ceeb8ccbd7
Layer gui reordered, point order can be defined, minor edit
fknauft
parents:
249
diff
changeset
|
268 qstr += ' ORDER BY 1' |
59 | 269 else: |
270 # TODO: proper quoting for names | |
271 qstr += ' ORDER BY "%s"'%sortBy.replace('"','') | |
245 | 272 bad_luck=True |
273 bl_counter=0 | |
274 while (bad_luck): | |
275 try: | |
276 data = self.executeSQL(qstr,idList) | |
277 bad_luck=False | |
278 bl_counter=bl_counter+1 | |
279 except: | |
255
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
280 if (bl_counter<5): |
245 | 281 bad_luck=True |
282 else: | |
283 bad_luck=False | |
284 | |
55 | 285 fieldMap = self.getFieldNameMap(data['fields']) |
261 | 286 geomdata=None |
247 | 287 if (geomField!="point"): |
261 | 288 # first check if the file is registered as geo-dataset (which then should have an attribute "the_geom") |
289 requeststring="select f_geometry_column from geometry_columns where f_table_schema=%s and f_table_name=%s " | |
290 geocolumn_res=self.executeSQL(requeststring,(schema,table)) | |
291 if len(geocolumn_res['rows'])>0: | |
292 geocolumn=geocolumn_res['rows'][0][0] | |
293 try: | |
275 | 294 geomstr="select astext(st_simplify(transform(%s,4326),0.05)) from %s.%s"%(geocolumn,sqlName(schema),sqlName(table)) # the string variables have to be added here and not in executeSQL! |
247 | 295 geomdata=self.executeSQL(geomstr) |
261 | 296 teststr=geomdata.values()[1][0] |
297 if (teststr == (u'MULTIPOLYGON EMPTY',)): | |
275 | 298 geomstr="select astext(st_simplify(transform(%s,4326),0.05)) from %s.%s"%(geocolumn,sqlName(schema),sqlName(table)) # the string variables have to be added here and not in executeSQL! |
261 | 299 geomdata=self.executeSQL(geomstr) |
300 | |
301 except: | |
302 try: | |
275 | 303 geomstr="select chgis.astext(chgis.st_simplify(chgis.transform(%s,4326),0.05)) from %s.%s"%(geocolumn,sqlName(schema),sqlName(table)) # the string variables have to be added here and not in executeSQL! |
261 | 304 geomdata=self.executeSQL(geomstr) |
305 except: | |
306 geomdata=None | |
233 | 307 |
308 if (gisIdField is None) and (latField is None or lonField is None) and geomField=='point': | |
55 | 309 # no fields given - choose automagically |
261 | 310 sql = "SELECT field_name FROM public.gis_table_meta_rows WHERE table_name = %s and gis_type = %s" |
55 | 311 # gis id in metadata first |
61 | 312 res = self.executeSQL(sql, (table,'gis_id')) |
55 | 313 if len(res['rows']) > 0: |
314 gisIdField = res['rows'][0][0] | |
255
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
315 # latitude in metadata |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
316 res = self.executeSQL(sql, (table,'coord_lat')) |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
317 if len(res['rows']) > 0: |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
318 latField = res['rows'][0][0] |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
319 # longitude in metadata |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
320 res = self.executeSQL(sql, (table,'coord_lon')) |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
321 if len(res['rows']) > 0: |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
322 lonField = res['rows'][0][0] |
93 | 323 |
233 | 324 if (gisIdField is None) and (latField is None or lonField is None) and geomField=='point': |
93 | 325 logging.warning("no entry in metadata table for table %s" % table) |
326 # still no fields - try field names | |
327 if 'latitude' in fieldMap and 'longitude' in fieldMap: | |
328 latField = 'latitude' | |
329 lonField = 'longitude' | |
330 elif 'x_coord' in fieldMap and 'y_coord' in fieldMap: | |
331 latField = 'x_coord' | |
332 lonField = 'y_coord' | |
333 else: | |
334 logging.error("getKMLdata unable to find position fields") | |
263 | 335 self.REQUEST.RESPONSE.write("Please define Position field") |
93 | 336 return None |
337 | |
55 | 338 |
339 # convert field names to row indexes | |
340 gisIdIdx = fieldMap.get(gisIdField,None) | |
341 latIdx = fieldMap.get(latField,None) | |
342 lonIdx = fieldMap.get(lonField,None) | |
117 | 343 the_geom=fieldMap.get("the_geom",None) |
55 | 344 logging.debug("gisidfield=%s idx=%s"%(gisIdField,gisIdIdx)) |
345 | |
346 # convert data | |
347 kmlData = [] | |
151 | 348 geom_list = {} |
261 | 349 # try: |
350 # if geomField=='poly' or geomField=='line': | |
351 # geom_list=geomdata.values()[1] | |
352 # except: | |
353 # return "no geomdata in RestDbGisApi Line 254" | |
354 | |
150 | 355 data_list=data['rows'] |
356 for k in range (len(data_list)): | |
357 dataset = data_list[k] | |
358 if len(geom_list)>k: | |
359 geom_value = geom_list[k] | |
360 | |
361 | |
261 | 362 if gisIdIdx != None and geomField!='point': |
363 gisID = dataset[gisIdIdx] | |
364 geomdata = self.getLineForChGisId(gisID) | |
365 | |
150 | 366 # for dataset in data['rows']: |
65 | 367 xCoord = 0.0 |
368 yCoord = 0.0 | |
255
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
369 if gisIdIdx != None and geomField=='point' : |
55 | 370 gisID = dataset[gisIdIdx] |
257
61525f0ca492
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
256
diff
changeset
|
371 if gisID != " " and gisID != " 0": |
255
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
372 coords=self.getPointForChGisId(gisID) |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
373 if coords!=None: |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
374 xCoord=coords[0] |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
375 yCoord=coords[1] |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
376 elif latIdx != None: |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
377 xCoord = dataset[lonIdx] |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
378 yCoord = dataset[latIdx] |
ec7b63319fad
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
254
diff
changeset
|
379 elif latIdx != None: |
55 | 380 xCoord = dataset[lonIdx] |
381 yCoord = dataset[latIdx] | |
382 | |
233 | 383 elif geomField=='point' : |
55 | 384 logging.error("getKMLdata unable to find position") |
385 return None | |
386 | |
233 | 387 if geomField=='point' : |
262 | 388 if type(xCoord).__name__=='string': |
389 if float(xCoord) == 0.0: | |
390 continue | |
391 else: | |
392 if xCoord == 0.0: | |
393 continue | |
394 if type(yCoord).__name__=='string': | |
395 if float(yCoord) == 0.0: | |
396 continue | |
397 else: | |
398 if yCoord == 0.0: | |
399 continue | |
55 | 400 |
401 kmlPlace = {} | |
402 | |
403 # description | |
404 desc = '' | |
150 | 405 |
262 | 406 timestring = '' |
264 | 407 beg_yr = '-9999' |
408 end_yr = '9999' | |
263 | 409 from_year = '' |
410 until_year = '' | |
411 sql = "SELECT field_name FROM public.gis_table_meta_rows WHERE table_name = %s and gis_type = %s" | |
412 # from_year and until_year in metadata first | |
264 | 413 try: |
273 | 414 res = self.executeSQL(sql, (table,from_year_name)) |
264 | 415 if len(res['rows']) > 0: |
416 from_year = res['rows'][0][0] | |
417 except: | |
418 from_year = "from_year_dummy" | |
419 try: | |
273 | 420 res = self.executeSQL(sql, (table,until_year_name)) |
264 | 421 if len(res['rows']) > 0: |
422 until_year = res['rows'][0][0] | |
423 except: | |
424 until_year = "until_year_dummy" | |
276 | 425 |
273 | 426 #DW added for testing E4D with names |
427 from_year=from_year_name | |
428 until_year=until_year_name | |
276 | 429 |
273 | 430 logging.debug("from_year:"+from_year) |
431 logging.debug("until_year:"+until_year) | |
150 | 432 for i in range (len(dataset)): |
433 value = dataset[i] | |
434 | |
55 | 435 name = data['fields'][i][0] |
58 | 436 #logging.debug("value=%s"%value) |
150 | 437 if name != 'the_geom': |
438 if value != None: | |
57 | 439 #if name.find('name')>-1: |
440 # desc += "<name>%s</name>\n"%value | |
441 # continue | |
442 #elif name.find('place')>-1: | |
443 # desc += "<name>%s</name>\n"%value | |
444 # continue | |
262 | 445 |
55 | 446 val = "%s: %s"%(name, value) |
273 | 447 logging.debug(name) |
187 | 448 value=unicode(value) |
263 | 449 if name == from_year: |
262 | 450 beg_yr= value |
263 | 451 if name == until_year: |
262 | 452 end_yr=value |
188 | 453 # If there is a link within the description data, create a valid href |
191 | 454 if value.find('http://')>-1: |
455 link_str_beg=value.find('http://') | |
456 link_str_end = -1 | |
457 link_str_end0=value.find(' ',link_str_beg) | |
458 link_str_end1=value.find('>',link_str_beg) | |
459 if link_str_end0 <link_str_end1: | |
460 link_str_end=link_str_end0 | |
461 else: | |
462 link_str_end=link_str_end1 | |
463 if link_str_end > -1: | |
464 link_str=value[link_str_beg:link_str_end] | |
207 | 465 val =name+": "+value[0:link_str_beg]+'<a href=' + link_str + '> ' + link_str.replace('http://','') + ' </a>' + value[link_str_end:] |
191 | 466 else: |
467 link_str=value[link_str_beg:] | |
207 | 468 val =name+': '+value[0:link_str_beg]+'<a href=' + link_str + '> ' + link_str.replace('http://','') + ' </a>' |
188 | 469 |
470 | |
57 | 471 #desc += kmlEncode(val) |
472 desc += val | |
55 | 473 desc += '<br/>\n' |
474 | |
57 | 475 #kmlPlace['description'] = "<![CDATA[%s]]>"%desc |
150 | 476 |
264 | 477 if end_yr!='9999': |
263 | 478 kmlPlace['TimeSpan0'] = '%s'%beg_yr |
479 kmlPlace['TimeSpan1'] = '%s'%end_yr | |
264 | 480 else: |
263 | 481 kmlPlace['TimeStamp'] = '%s'%beg_yr |
124 | 482 |
133 | 483 if geomField=='point': |
278 | 484 #kmlPlace['description'] = "<![CDATA[%s]]>"%desc |
485 kmlPlace['description'] = desc | |
193 | 486 |
133 | 487 kmlPlace['icon'] = '#marker_icon_'+colorField |
488 kmlPlace['coord_x'] = str(xCoord) | |
489 kmlPlace['coord_y'] = str(yCoord) | |
258
ed99a2468264
GIS-Links from MPDL-Documents now served by Mappit-Server
fknauft
parents:
257
diff
changeset
|
490 kmlPlace['coord_z'] = '50' |
134 | 491 kmlData.append(kmlPlace) |
261 | 492 if (geomField=='poly' or geomField=='line') and geomdata is not None: |
493 polys=str(geomdata).split('(') | |
144 | 494 aaa=len(polys) |
142 | 495 for poly in polys: |
150 | 496 kmlPlace = {} |
497 kmlPlace['description'] = desc | |
152 | 498 coords=poly.replace(')','').replace("'","").split(',') |
150 | 499 coord_string='' |
144 | 500 if len(coords)>1: |
146 | 501 for coord in coords: |
502 coord=coord.split(' ') | |
503 try: | |
504 x_coord=coord[0] | |
505 y_coord=coord[1] | |
506 except: | |
507 break | |
150 | 508 coord_string+=x_coord+','+y_coord+','+'0 ' |
509 if coord_string != '': | |
510 kmlPlace['LinearRing']=coord_string | |
245 | 511 kmlPlace['lineColor']='#'+colorField+'_'+geomField |
150 | 512 kmlData.append(kmlPlace) |
262 | 513 |
514 | |
55 | 515 #logging.debug("kmlData=%s"%(repr(kmlData))) |
516 return kmlData | |
58 | 517 |
518 def getPointForChGisId(self, gis_id): | |
260
e9a1ac7d2ab2
Bug resolved in request point_id from Harvard ChGIS
fknauft
parents:
259
diff
changeset
|
519 """returns coordinate pair for given gis_id""" # gets called by getKml |
59 | 520 def getPoint(id): |
247 | 521 str_gis_id=str(id).split('.')[0] |
522 sql="SELECT x_coord,y_coord FROM chgis.chgis_coords WHERE gis_id LIKE CAST('%s' AS text)"%str(str_gis_id) | |
523 # logging.error("sql:",sql) | |
524 # res = self.executeSQL(sql, (str(str_gis_id),)) | |
525 res = self.executeSQL(sql) | |
59 | 526 if len(res['rows']) > 0: |
527 return res['rows'][0] | |
247 | 528 else: |
529 #logging.error("error on sql:",sql%(str(str_gis_id),)) | |
530 return None | |
55 | 531 |
58 | 532 if gis_id is None or gis_id == "": |
533 return None | |
261 | 534 if len(str(gis_id)) < 4: |
260
e9a1ac7d2ab2
Bug resolved in request point_id from Harvard ChGIS
fknauft
parents:
259
diff
changeset
|
535 return None |
58 | 536 |
59 | 537 # try gis_id |
538 coords = getPoint(gis_id) | |
539 if coords is None: | |
58 | 540 # try to clean gis_id... |
247 | 541 gis_id_short = re.sub(r'[^0-9]','',gis_id) |
58 | 542 # try again |
247 | 543 coords = getPoint(gis_id_short) |
59 | 544 if coords is None: |
247 | 545 #logging.error("CH-GIS ID %s not found!"%str(gis_id_short)) |
546 | |
547 # this will ask the Harvard-Service for the Coords of this gis_id and write it into our coords-list | |
548 try: | |
549 coords=self.getCoordsFromREST_gisID(gis_id) | |
550 #logging.error("coords from REST"%str(coords)) | |
551 except: | |
552 logging.error("coords from REST did not work for "%str(gis_id)) | |
553 if coords[0] is None: | |
554 logging.error("CH-GIS ID %s not found in Harvard"%str(gis_id)) | |
555 else: | |
556 try: | |
557 SQL="INSERT INTO chgis.chgis_coords (gis_id,x_coord,y_coord) VALUES (CAST(%s AS text),CAST(%s AS numeric),CAST(%s AS numeric))" | |
558 SQL_analyze="ANALYZE chgis.chgis_coords" | |
559 self.executeSQL(SQL,(str(gis_id_short),str(coords[0][1]),str(coords[0][0])),False) | |
560 self.executeSQL(SQL_analyze,(),False) | |
561 except: | |
562 logging.error("Could not write into chgis_coords: ", str(gis_id_short)) | |
563 logging.error("coords[0][0]:"%coords[0][0]) | |
564 logging.error("coords[0][1]:"%coords[0][1]) | |
565 return coords[0] | |
566 coords_test = getPoint(gis_id) | |
567 #logging.error("SQL results now:", str(coords_test)) | |
568 return coords[0] | |
58 | 569 |
59 | 570 return coords |
571 | |
55 | 572 |
261 | 573 def getLineForChGisId(self, gis_id): |
574 """returns line/poly coordinates for given gis_id""" # gets called by getKml | |
575 def getLine(id): | |
576 str_gis_id=str(id).split('.')[0] | |
577 sql="SELECT astext(st_simplify(transform(the_geom,4326),0.05)) FROM chgis.chgis_linesandpolys WHERE gis_id LIKE CAST('%s' AS text)"%(str_gis_id) | |
578 # logging.error("sql:",sql) | |
579 # res = self.executeSQL(sql, (str(str_gis_id),)) | |
580 res = self.executeSQL(sql) | |
581 if len(res['rows']) > 0: | |
582 return res['rows'][0] | |
583 else: | |
584 #logging.error("error on sql:",sql%(str(str_gis_id),)) | |
585 return None | |
586 | |
587 if gis_id is None or gis_id == "": | |
588 return None | |
589 if len(str(gis_id)) < 4: | |
590 return None | |
591 | |
592 # try gis_id | |
593 line_coords = getLine(gis_id) | |
594 if line_coords is None: | |
595 # try to clean gis_id... | |
596 gis_id_short = re.sub(r'[^0-9]','',gis_id) | |
597 # try again | |
598 line_coords = getLine(gis_id_short) | |
599 if line_coords is None: | |
600 logging.error("CH-GIS ID %s not found!"%(gis_id_short)) | |
601 | |
602 | |
603 return line_coords | |
604 | |
59 | 605 ## legacy methods... |
606 | |
207 | 607 def trydatahas_key(self,data,index,key_string): |
273 | 608 logging.debug("trying:"+key_string) |
207 | 609 try: |
610 return data[index].has_key(key_string) | |
611 except: | |
612 return 'false' | |
43 | 613 |
614 # End for GoogleMaps creation | |
615 | |
616 def RESTwrite2File(self,datadir, name,text): | |
617 logging.debug("RESTwrite2File datadir=%s name=%s"%(datadir,name)) | |
618 try: | |
619 import cStringIO as StringIO | |
620 except: | |
621 import StringIO | |
622 | |
623 # make filehandle from string | |
624 textfile = StringIO.StringIO(text) | |
625 fileid=name | |
626 if fileid in datadir.objectIds(): | |
627 datadir.manage_delObjects(fileid) | |
628 fileInZope=datadir.manage_addFile(id=fileid,file=textfile) | |
629 return "Write successful" | |
630 | |
631 def manage_editRestDbGisApi(self, title=None, connection_id=None, | |
632 REQUEST=None): | |
633 """Change the object""" | |
634 if title is not None: | |
635 self.title = title | |
636 | |
637 if connection_id is not None: | |
638 self.connection_id = connection_id | |
639 | |
640 #checkPermission=getSecurityManager().checkPermission | |
641 REQUEST.RESPONSE.redirect('manage_main') | |
642 | |
643 | |
644 manage_addRestDbGisApiForm=PageTemplateFile('zpt/addRestDbGisApi',globals()) | |
645 | |
646 def manage_addRestDbGisApi(self, id, title='', label='', description='', | |
647 createPublic=0, | |
648 createUserF=0, | |
649 REQUEST=None): | |
650 """Add a new object with id *id*.""" | |
651 | |
652 ob=RestDbGisApi(str(id),title) | |
653 self._setObject(id, ob) | |
654 | |
655 #checkPermission=getSecurityManager().checkPermission | |
656 REQUEST.RESPONSE.redirect('manage_main') | |
657 | |
247 | 658 |
659 | |
660 |