def create(root: gws.IRoot, cfg: gws.Config, parent: gws.Node = None, shared: bool = False) -> Object: key = gws.get(cfg, 'uid') or gws.get(cfg, 'path') or gws.sha256( gws.get(cfg, 'text', default='')) return root.create_object('gws.ext.template', cfg, parent, shared, key)
def _res_or_scale(cfg, r, s): x = gws.get(cfg, r) if x: return x x = gws.get(cfg, s) if x: return units.scale_to_res(x)
def _entries(root: gws.IRoot, mpx_config, layer_uids=None): caches: gws.Dict[str, Entry] = {} for layer in root.find_all('gws.ext.layer'): if layer_uids and layer.uid not in layer_uids: continue for uid, cc in mpx_config['caches'].items(): if cc.get('disable_storage') or gws.get(layer, 'cache_uid') != uid: continue if uid in caches: caches[uid].layers.append(layer) continue cfg = gws.get(layer, 'cache') grids = [mpx_config['grids'][g] for g in cc['grids']] crs = grids[0]['srs'].replace(':', '') caches[uid] = Entry( uid=uid, layers=[layer], mpx_cache=cc, mpx_grids=grids, config=vars(cfg) if cfg else {}, counts={}, dirname=f'{gws.MAPPROXY_CACHE_DIR}/{uid}_{crs}', ) return list(caches.values())
def _explicit_resolutions(cfg): ls = gws.get(cfg, 'resolutions') if ls: return ls ls = gws.get(cfg, 'scales') if ls: return [units.scale_to_res(x) for x in ls]
def _configure_extent(obj, crs: gws.ICrs, default_ext): layers = gws.get(obj, 'layers') or [] # we have an explicit extent provided in the config config_ext = obj.var('extent') if config_ext: ext = gws.gis.extent.from_list(config_ext) if not ext: raise gws.Error(f'{obj.uid!r}: invalid extent {config_ext!r}') # configure sublayers using config_ext as a default for la in layers: _configure_extent(la, crs, ext) obj.extent = ext return obj.extent if layers: # no config extent, configure sublayers using the current default extent # set obj.extent to the sum of sublayers' extents layer_ext_list = [] for la in layers: layer_ext = _configure_extent(la, crs, default_ext) if layer_ext: layer_ext_list.append(layer_ext) if layer_ext_list: obj.extent = gws.gis.extent.merge(layer_ext_list) else: obj.extent = default_ext return obj.extent # obj is a leaf layer and has no configured extent # check if it has an own extent (from its source) own_bounds: gws.Bounds = gws.get(obj, 'own_bounds') if own_bounds: own_ext = own_bounds.extent buf = obj.var('extentBuffer', with_parent=True) if buf: own_ext = gws.gis.extent.buffer(own_ext, buf) own_ext = gws.gis.extent.transform(own_ext, own_bounds.crs, crs) obj.extent = own_ext return obj.extent # obj is a leaf layer and has neither configured nor own extent # try using the default extent if default_ext: obj.extent = default_ext return obj.extent # no extent can be computed, it will be set to the map extent later on return None
def _before_init(cfg): autorun = gws.get(cfg, 'server.autoRun') if autorun: gws.log.info(f'AUTORUN: {autorun!r}') cmds = shlex.split(autorun) gws.lib.os2.run(cmds, echo=True) timezone = gws.get(cfg, 'server.timeZone') if timezone: gws.lib.date.set_system_time_zone(timezone)
def search_config(self, source_layers): default = { 'type': 'qgiswms', '_provider': self, '_source_layers': source_layers, } if len(self.source_layers) > 1 or self.source_layers[0].is_group: return default sl = source_layers[0] ds = sl.data_source prov = ds.get('provider') if prov not in self.direct_search: return default if prov == 'wms': layers = ds.get('layers') if layers: return { 'type': 'wms', 'sourceLayers': { 'names': ds['layers'] }, 'url': self.make_wms_url(ds['url'], ds['params']), } if prov == 'postgres': tab = sl.data_source.get('table') # 'table' can also be a select statement, in which case it might be enclosed in parens if not tab or tab.startswith('(') or tab.upper().startswith( 'SELECT '): return return {'type': 'qgispostgres', '_data_source': ds} if prov == 'wfs': cfg = { 'type': 'wfs', 'url': ds['url'], } if gws.get(ds, 'typeName'): cfg['sourceLayers'] = {'names': [ds['typeName']]} crs = gws.get(ds, 'params.srsname') inv = gws.get(ds, 'params.InvertAxisOrientation') if inv == '1' and crs: cfg['invertAxis'] = [crs] return cfg gws.log.warn(f'directSearch not supported for {prov!r}') return default
def _load_db_meta(self): metas = {} meta_dates = {} def _date(s): return gws.lib.date.to_iso(gws.lib.date.to_utc(s), with_tz='Z') with self.db.connect() as conn: rs = conn.select(f'''SELECT * FROM {conn.quote_table(self.meta_table.name)}''') for r in rs: au_uid = r['_au'] metas[au_uid] = gws.lib.metadata.from_dict(gws.lib.json2.from_string(r['meta'])) meta_dates[au_uid] = _date(r['_updated']) rs = conn.select(f''' SELECT _au, MIN(_updated) AS min_updated, MAX(_updated) AS max_updated, MIN(CASE WHEN {self.time_col} != '' THEN DATE({self.time_col}) ELSE _updated END) AS min_time, MAX(CASE WHEN {self.time_col} != '' THEN DATE({self.time_col}) ELSE _updated END) AS max_time FROM {conn.quote_table(self.plan_table.name)} GROUP BY _au ''') for r in rs: au_uid = r['_au'] if au_uid not in metas: metas[au_uid] = gws.Values() metas[au_uid].dateCreated = _date(r['min_updated']) metas[au_uid].dateUpdated = _date(r['max_updated']) md = meta_dates.get(au_uid) if md and md < metas[au_uid].dateCreated: metas[au_uid].dateCreated = md if md and md > metas[au_uid].dateUpdated: metas[au_uid].dateUpdated = md metas[au_uid].dateBegin = _date(r['min_time']) metas[au_uid].dateEnd = _date(r['max_time']) # extend metadata for "our" objects for obj in self.root.find_all(): uid = gws.get(obj, 'uid') or '' if uid and gws.get(obj, 'meta'): for au_uid, meta in metas.items(): if uid.endswith(au_uid): obj.meta = gws.lib.metadata.extend(meta, obj.meta) if gws.get(obj, 'update_sequence'): obj.update_sequence = meta.dateUpdated
def _create_index(self): self.index = [] for uid, md in self.records.items(): s = gws.get(md, 'title') if s: self.index.append(['title', s, s.lower(), uid]) s = gws.get(md, 'abstract') if s: self.index.append(['abstract', s, s.lower(), uid]) s = gws.get(md, 'keywords') if s: for kw in s: self.index.append(('subject', kw, kw.lower(), uid))
def _get_elements(self, parent_client): elements = self.var('elements') if elements: return elements if not parent_client: return [] elements = list(gws.get(parent_client, 'elements', [])) add = self.var('addElements', default=[]) for c in add: n = self._find_element(elements, c.tag) if n >= 0: elements.pop(n) if c.before: n = self._find_element(elements, c.before) if n >= 0: elements.insert(n, c) elif c.after: n = self._find_element(elements, c.after) if n >= 0: elements.insert(n + 1, c) else: elements.append(c) remove = self.var('removeElements', default=[]) remove_tags = [c.tag for c in remove] return [e for e in elements if e.tag not in remove_tags]
def parse_dict(d: dict, trusted, with_strict_mode) -> dict: res = dict(_DEFAULTS) for key, val in d.items(): if val is None: continue k = key.replace('-', '_') if k.startswith('__'): k = k[2:] fn = gws.get(_ParseFunctions, k) if not fn: err = f'style: invalid css property {key!r}' if with_strict_mode: raise gws.Error(err) else: gws.log.error(err) continue try: v = fn(val, trusted) if v is not None: res[k] = v except Exception as exc: err = f'style: invalid css value for {key!r}' if with_strict_mode: raise gws.Error(err) from exc else: gws.log.error(err) return res
def configure(self): parent_client = self.var('parentClient') self.elements = self.create_children(Element, self._get_elements(parent_client)) opts = self.var('options') if not opts and parent_client: opts = gws.get(parent_client, 'options', {}) self.options = opts or {}
def _run( req: gws.IWebRequest, args: gws.SearchArgs, provider: gws.ISearchProvider, total_limit, features, layer: t.Optional[gws.ILayer] = None, project: t.Optional[gws.IProject] = None, ): args.limit = total_limit - len(features) if args.limit <= 0: raise _LimitExceeded() gws.log.debug( 'SEARCH_BEGIN: prov=%r layer=%r limit=%d' % (gws.get(provider, 'uid'), gws.get(layer, 'uid'), args.limit)) if not req.user.can_use(provider, context=layer or project): gws.log.debug('SEARCH_END: NO_ACCESS') return if not provider.can_run(args): gws.log.debug(f'SEARCH_END: N_A') return try: fs: t.List[gws.IFeature] = provider.run(args, layer) or [] except: gws.log.exception('SEARCH_FAILED') return tt = provider.templates or (layer.templates if layer else None) dm = provider.data_model or (layer.data_model if layer else None) for f in fs: f.layer = layer f.category = provider.title or (layer.title if layer else '') f.templates = tt f.data_model = dm gws.log.debug('SEARCH_END, found=%r', len(fs)) features.extend(fs)
def _xml_error(self, err: Exception): try: status = int(gws.get(err, 'code', 500)) except Exception: status = 500 description = xml2.encode( gws.get(err, 'description') or f'Error {status}') xml = ( f'<?xml version="1.0" encoding="UTF-8"?>' + f'<ServiceExceptionReport>' + f'<ServiceException code="{status}">{description}</ServiceException>' + f'</ServiceExceptionReport>') # @TODO status, check OGC 17-007r1 return gws.ContentResponse(mime=gws.lib.mime.XML, content=xml, status=200)
def create(root: gws.IRoot): mc = _Config() for layer in root.find_all('gws.ext.layer'): m = getattr(layer, 'mapproxy_config') if m: m(mc) cfg = mc.to_dict() if not cfg.get('layers'): return crs: t.List[gws.ICrs] = [] for p in root.find_all('gws.base.map'): crs.append(gws.get(p, 'crs')) for p in root.find_all('gws.ext.ows.service'): crs.extend(gws.get(p, 'supported_crs', default=[])) cfg['services']['wms']['srs'] = sorted(set(c.epsg for c in crs)) return cfg
def _get_crs(self, js): p = js.get('crs') if not p: return if p.get('type') == 'name': crs = gws.gis.crs.get(gws.get(p, 'properties.name')) if crs: return crs raise gws.Error(f'unsupported geojson crs format')
def _collect_metadata(self): # collect objects whose metadata should be published in the catalog # # - object should have `metadata` # - object must be public # - `metadata` should have `catalogUid` # - `metadata.metaLinks` should be empty # # `metadata.metaLinks[0]` will be set to our csw url self.records = {} for obj in self.root.find_all(): md: gws.lib.metadata.Metadata = gws.get(obj, 'metadata') if not md or not md.get('catalogUid'): continue cid = gws.to_uid(md.get('catalogUid')) if md.get('metaLinks'): gws.log.debug(f'csw: skip {cid}: has metalinks') continue if not gws.is_public_object(obj): gws.log.debug(f'csw: skip {cid}: not public') continue md.set('catalogUid', cid) md.set('catalogCitationUid', cid) md.set('metaLinks', [self._make_link(cid)]) extent = gws.get(obj, 'extent') or gws.get(obj, 'map.extent') crs = gws.get(obj, 'crs') or gws.get(obj, 'map.crs') if extent and crs: md.set('extent4326', gws.gis.extent.transform_to_4326(extent, crs)) md.set('crs', crs) # @TODO get boundingPolygonElement somehow self.records[cid] = md
def _handle_error(req: WebRequest, err: gws.base.web.error.HTTPException) -> WebResponse: # @TODO: image errors site = t.cast(gws.base.web.site.Object, req.site) if req.output_struct_type: return req.struct_response( gws.Response(error=gws.ResponseError( status=err.code, info=gws.get(err, 'description', '')))) if not site.error_page: return req.error_response(err) try: context = {'request': req, 'error': err.code} res = site.error_page.render(gws.TemplateRenderInput(context=context)) return req.content_response( gws.ContentResponse(content=res.content, mime=res.mime, status=err.code)) except: gws.log.exception() return req.error_response(gws.base.web.error.InternalServerError())
def get_tile_url(self): resource_url = gws.get(self.source_layer, 'resource_urls.tile') if resource_url: return (resource_url .replace('{TileMatrixSet}', self.tile_matrix_set.uid) .replace('{TileMatrix}', '%(z)02d') .replace('{TileCol}', '%(x)d') .replace('{TileRow}', '%(y)d') .replace('{Style}', self.style_name or 'default')) operation = self.provider.operation(gws.OwsVerb.GetTile) params = { 'SERVICE': 'WMTS', 'REQUEST': 'GetTile', 'VERSION': self.provider.version, 'LAYER': self.source_layer.name, 'FORMAT': self.source_layer.image_format or 'image/jpeg', 'TILEMATRIXSET': self.tile_matrix_set.uid, 'TILEMATRIX': '%(z)02d', 'TILECOL': '%(x)d', 'TILEROW': '%(y)d', } if self.style_name: params['STYLE'] = self.style_name pu = gws.lib.net.parse_url(operation.get_url) params.update(pu.params) # NB cannot use as_query_string because of the MP's percent formatting qs = '&'.join(k + '=' + str(v or '') for k, v in params.items()) return gws.lib.net.make_url(pu, params={}) + '?' + qs
def __init__(self, options, instance, cache_lifetime=None): self.options = options self.instance = instance or 'none' self.cache_lifetime = cache_lifetime self.position = gws.get(self.options, 'position')
def _pval(props, key): return gws.get(props, key.lower())
def _set_default_extent(obj, extent): if not gws.get(obj, 'extent'): obj.extent = extent for la in gws.get(obj, 'layers', []): _set_default_extent(la, extent)