Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge remote-tracking branch 'origin/2.3' #3936

Merged
merged 24 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3ff0af7
Send cookies only on https
sbrunner Jul 5, 2018
ad5ce8a
Fix the log message
sbrunner Jul 6, 2018
21a400a
Secure the plugin against error
sbrunner Jul 6, 2018
f2f26ff
Fix role and restriction area
sbrunner Jul 6, 2018
680b065
Fix code style
sbrunner Jul 6, 2018
391c525
Makes docker-compose-run compatible with Windows
sbrunner Jul 16, 2018
67d09a5
Add editor config file
sbrunner Jul 16, 2018
ec72647
Merge pull request #3918 from camptocamp/editorconfig
sbrunner Jul 17, 2018
546360f
use variable web_protocol (like in docker template)
jwkaltz Jul 17, 2018
5ff2cbd
Fix OpenLayers in the admin interface
sbrunner Jul 17, 2018
8d3ef1b
Add WMTS queryable zoom limits documentation
kalbermattenm Jul 18, 2018
954b4ba
Don't have dupplicated fulltextsearchUrl
sbrunner Jul 18, 2018
35c9e46
Do an xmllint on the jasper report print templates
sbrunner Jul 18, 2018
6ee1702
Merge pull request #3928 from kalbermattenm/doc
sbrunner Jul 19, 2018
d2f284c
Merge pull request #3921 from camptocamp/small_fix
jwkaltz Jul 20, 2018
26f2b51
Merge pull request #3905 from camptocamp/secure-cookie
sbrunner Jul 24, 2018
8356823
Merge pull request #3917 from camptocamp/win
sbrunner Jul 24, 2018
7387f5f
Merge pull request #3923 from camptocamp/fix-admin-ol
sbrunner Jul 24, 2018
82f675d
Merge pull request #3926 from camptocamp/dupplicate-fulltextsearchUrl
sbrunner Jul 24, 2018
c9ba016
Merge pull request #3927 from camptocamp/print-xmllint
sbrunner Jul 24, 2018
88787d7
Factorise assert plugin initialised
sbrunner Jul 24, 2018
fceb9a8
Merge pull request #3912 from camptocamp/qgis
sbrunner Jul 24, 2018
d217d24
Merge remote-tracking branch 'origin/2.3'
sbrunner Jul 26, 2018
4f34d09
Directly use the npm package, update ngeo
sbrunner Jul 26, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
!admin/README.md
!admin/requirements.txt
!admin/requirements-dev.txt
!admin/npm-packages
**/__pycache__/
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.js]
indent_size = 2

[Makefile]
indent_style = tab
5 changes: 4 additions & 1 deletion Dockerfile.mako
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ COPY commons /opt/c2cgeoportal_commons
COPY geoportal /opt/c2cgeoportal_geoportal
COPY admin /opt/c2cgeoportal_admin

RUN chmod go+r -R /opt/c2cgeoportal_commons /opt/c2cgeoportal_geoportal && \
RUN \
(cd /opt/c2cgeoportal_admin/; npm install --no-optional `cat npm-packages`) && \
npm cache clear && \
chmod go+r -R /opt/c2cgeoportal_commons /opt/c2cgeoportal_geoportal /opt/c2cgeoportal_admin && \
ln -s /opt/c2cgeoportal_commons/c2cgeoportal_commons/alembic /opt && \
pip install --disable-pip-version-check --no-cache-dir --no-deps \
--editable=/opt/c2cgeoportal_commons \
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ npm-packages: ngeo package.json
npm-packages --ngeo \
coveralls gaze jasmine-core jsdoc jsdom karma karma-chrome-launcher karma-coverage \
karma-jasmine karma-sourcemap-loader karma-webpack \
--src=ngeo/package.json --src=package.json --dst=$@
--src=ngeo/package.json --dst=$@
echo googshift eslint-plugin-googshift >> $@

admin/npm-packages: ngeo package.json
Expand Down
5 changes: 5 additions & 0 deletions doc/administrator/administrate.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ To make the WMTS queryable, you should add the following ``Metadata``:
* ``ogcServer`` with the name of the used ``OGC server``,
* ``wmsLayers`` or ``queryLayers`` with the layers to query (groups not supported).

It is possible to give some scale limits for the queryable layers by setting
a ``minResolution`` and/or a ``maxResolution Metadata`` value(s) for the
WMTS layer. These values correspond to the WMTS layer resolution(s) which should
be the zoom limit.

Print WMTS in high quality
~~~~~~~~~~~~~~~~~~~~~~~~~~
To print the layers in high quality, you should add the following ``Metadata``:
Expand Down
2 changes: 1 addition & 1 deletion docker/build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ LABEL maintainer Camptocamp "info@camptocamp.com"
RUN \
. /etc/os-release && \
apt-get update && \
apt-get install --assume-yes --no-install-recommends tree apt-transport-https gettext sudo && \
apt-get install --assume-yes --no-install-recommends tree apt-transport-https gettext sudo libxml2-utils && \
echo "deb https://deb.nodesource.com/node_6.x ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/nodesource.list && \
curl --silent https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
# Docker source list should be like it but actually it's empty...
Expand Down
130 changes: 77 additions & 53 deletions docker/qgisserver/geomapfish_plugin/accesscontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,60 +43,74 @@ def __init__(self, server_iface):

self.server_iface = server_iface
self.area_cache = {}
self.layers = None

if "GEOMAPFISH_OGCSERVER" not in os.environ:
raise GMFException("The environment variable 'GEOMAPFISH_OGCSERVER' is not defined.")

print("Use OGC server named '{}'".format(os.environ["GEOMAPFISH_OGCSERVER"]))

config.init(os.environ.get('GEOMAPFISH_CONFIG', '/etc/qgisserver/geomapfish.yaml'))
self.srid = config.get('srid')

from c2cgeoportal_commons.models.main import LayerWMS, OGCServer
configure_mappers()

engine = sqlalchemy.create_engine(config.get('sqlalchemy_slave.url'))
session_factory = sessionmaker()
session_factory.configure(bind=engine)
self.DBSession = scoped_session(session_factory)

self.ogcserver = self.DBSession.query(OGCServer) \
.filter(OGCServer.name == os.environ["GEOMAPFISH_OGCSERVER"]) \
.one()
try:
if "GEOMAPFISH_OGCSERVER" not in os.environ:
raise GMFException("The environment variable 'GEOMAPFISH_OGCSERVER' is not defined.")

print("Use OGC server named '{}'".format(os.environ["GEOMAPFISH_OGCSERVER"]))

config.init(os.environ.get('GEOMAPFISH_CONFIG', '/etc/qgisserver/geomapfish.yaml'))
self.srid = config.get('srid')

from c2cgeoportal_commons.models.main import LayerWMS, OGCServer
configure_mappers()

engine = sqlalchemy.create_engine(config.get('sqlalchemy_slave.url'))
session_factory = sessionmaker()
session_factory.configure(bind=engine)
self.DBSession = scoped_session(session_factory)

self.ogcserver = self.DBSession.query(OGCServer) \
.filter(OGCServer.name == os.environ["GEOMAPFISH_OGCSERVER"]) \
.one()

layers = {}
# TODO manage groups ...
for layer in self.DBSession.query(LayerWMS).filter(LayerWMS.ogc_server_id == self.ogcserver.id).all():
for name in layer.layer.split(','):
if name not in layers:
layers[name] = []
layers[name].append(layer)
QgsMessageLog.logMessage('[accesscontrol] layers: {}'.format(
json.dumps(dict([(k, [l.name for l in v]) for k, v in layers.items()]), sort_keys=True, indent=4)
))
self.layers = layers

self.layers = {}
# TODO manage groups ...
for layer in self.DBSession.query(LayerWMS).filter(LayerWMS.ogc_server_id == self.ogcserver.id).all():
for name in layer.layer.split(','):
if name not in self.layers:
self.layers[name] = []
self.layers[name].append(layer)
QgsMessageLog.logMessage('[accesscontrol] layers: {}'.format(
json.dumps(self.layers, sort_keys=True, indent=4)
))
except Exception as e:
QgsMessageLog.logMessage(traceback.format_tb(e))
QgsMessageLog.logMessage(str(e))
raise

server_iface.registerAccessControl(self, int(os.environ.get("GEOMAPFISH_POSITION", 100)))

def assert_plugin_initialised(self):
if self.layers is None:
raise Exception("The plugin is not initialised")

def get_role(self):
from c2cgeoportal_commons.models.main import Role
parameters = self.serverInterface().requestHandler().parameterMap()
return self.DBSession.query(Role).get(parameters['ROLE_ID'])
return self.DBSession.query(Role).get(parameters['ROLE_ID']) if 'ROLE_ID' in parameters else None

def get_restriction_areas(self, gmf_layers, rw=False, role=False):
@staticmethod
def get_restriction_areas(gmf_layers, rw=False, role=None):
"""
None => full access
[] => no access
shapely.ops.cascaded_union(result) => geom of access
"""
if role is False:
role = self.get_role()

if role is None:
return []

restriction_areas = []
for layer in gmf_layers:
for restriction_area in layer.restrictionareas:
if role in restriction_area.roles and rw is False or restriction_area.readwrite is True:
if restriction_area.area is None:
return None
return []
else:
restriction_areas.append(geoalchemy2.shape.to_shape(
restriction_area.area
Expand All @@ -106,16 +120,16 @@ def get_restriction_areas(self, gmf_layers, rw=False, role=False):

def get_area(self, layer, rw=False):
role = self.get_role()
key = (layer.name(), role.name, rw)
key = (layer.name(), role.name if role is not None else None, rw)

if key in self.area_cache:
return self.area_cache[key]

gmf_layers = self.layers[layer.name()]
restriction_areas = self.get_restriction_areas(gmf_layers, role=role)

if restriction_areas is None:
self.area_cache[key] = None
if len(restriction_areas) == 0:
self.area_cache[key] = []
return None

area = ops.unary_union(restriction_areas).wkt
Expand All @@ -126,6 +140,8 @@ def layerFilterSubsetString(self, layer): # NOQA
""" Return an additional subset string (typically SQL) filter """
QgsMessageLog.logMessage("layerFilterSubsetString {}".format(layer.dataProvider().storageType()))

self.assert_plugin_initialised()

try:
if layer.dataProvider().storageType() not in self.EXPRESSION_TYPE:
return None
Expand All @@ -146,14 +162,17 @@ def layerFilterSubsetString(self, layer): # NOQA
return "ST_intersects({}, {})".format(
QgsDataSourceUri(layer.dataProvider().dataSourceUri()).geometryColumn(), area
)
except Exception:
QgsMessageLog.logMessage(traceback.format_exc())
except Exception as e:
QgsMessageLog.logMessage(traceback.format_tb(e))
QgsMessageLog.logMessage(str(e))
raise

def layerFilterExpression(self, layer): # NOQA
""" Return an additional expression filter """
QgsMessageLog.logMessage("layerFilterExpression {}".format(layer.dataProvider().storageType()))

self.assert_plugin_initialised()

try:
if layer.dataProvider().storageType() in self.EXPRESSION_TYPE:
return None
Expand All @@ -164,21 +183,24 @@ def layerFilterExpression(self, layer): # NOQA
return None

QgsMessageLog.logMessage("intersects($geometry, geom_from_wkt('{}'))".format(area))
#return "geometry = '{}'".format(ops.unary_union(restriction_areas).wkt)
#return "fid = 2"
# return "geometry = '{}'".format(ops.unary_union(restriction_areas).wkt)
# return "fid = 2"
# TODO cache the union
# TODO verify the geometry
return "intersects($geometry, transform(geom_from_wkt('{}'), 'EPSG:{}', 'EPSG:{}')".format(
area, self.srid, layer.crs().projectionAcronym()
)
except Exception:
QgsMessageLog.logMessage(traceback.format_exc())
except Exception as e:
QgsMessageLog.logMessage(traceback.format_tb(e))
QgsMessageLog.logMessage(str(e))
raise

def layerPermissions(self, layer): # NOQA
""" Return the layer rights """
QgsMessageLog.logMessage("layerPermissions {}".format(layer.name()))

self.assert_plugin_initialised()

try:
rights = QgsAccessControlFilter.LayerPermissions()
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = False
Expand All @@ -191,20 +213,19 @@ def layerPermissions(self, layer): # NOQA
if l.public is True:
rights.canRead = True

role = self.get_role()
if not rights.canRead:
role = self.get_role()
restriction_areas = self.get_restriction_areas(gmf_layers, role=role)
if restriction_areas is not None and len(restriction_areas) == 0:
return rights
rights.canRead = True
if len(restriction_areas) > 0:
rights.canRead = True

restriction_areas = self.get_restriction_areas(gmf_layers, rw=True, role=role)
rights.canInsert = rights.canUpdate = rights.canDelete = \
restriction_areas is None or len(restriction_areas) > 0
rights.canInsert = rights.canUpdate = rights.canDelete = len(restriction_areas) > 0

return rights
except Exception:
QgsMessageLog.logMessage(traceback.format_exc())
except Exception as e:
QgsMessageLog.logMessage(traceback.format_tb(e))
QgsMessageLog.logMessage(str(e))
raise

@staticmethod
Expand All @@ -220,12 +241,15 @@ def allowToEdit(self, layer, feature): # NOQA
""" Are we authorise to modify the following geometry """
QgsMessageLog.logMessage("allowToEdit")

self.assert_plugin_initialised()

try:
area = self.get_area(layer, rw=True)

return area is None or area.intersect(feature.geom)
except Exception:
QgsMessageLog.logMessage(traceback.format_exc())
except Exception as e:
QgsMessageLog.logMessage(traceback.format_tb(e))
QgsMessageLog.logMessage(str(e))
raise

def cacheKey(self): # NOQA
Expand Down
2 changes: 1 addition & 1 deletion geoportal/c2cgeoportal_geoportal/lib/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def create_authentication(settings):
callback=defaultgroupsfinder,
cookie_name=settings["authtkt_cookie_name"],
timeout=timeout, max_age=timeout, reissue_time=reissue_time,
hashalg="sha512", http_only=True
hashalg="sha512", http_only=True, secure=True,
)
basic_authentication_policy = BasicAuthAuthenticationPolicy(c2cgeoportal_check)
policies = [cookie_authentication_policy, basic_authentication_policy]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import subprocess

os.environ["HOME_DIR"] = os.environ["HOME"]
os.environ['USER_NAME'] = getpass.getuser()
os.environ['USER_ID'] = str(os.getuid())
os.environ['GROUP_ID'] = str(os.getgid())
os.environ['USER_ID'] = str(os.getuid()) if os.name == "posix" else "1000"
os.environ['GROUP_ID'] = str(os.getgid()) if os.name == "posix" else "1000"

try:
subprocess.check_call([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ vars:
partitionlimit: 5
routes: &routes
authenticationBaseUrl: base
fulltextsearchUrl: fulltextsearch
gmfLayersUrl: layers_root
gmfRasterUrl: raster
gmfProfileCsvUrl: profile.csv
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ MAP
METADATA
"wms_title" "changeme"
"wms_abstract" "changeme"
"wms_onlineresource" "http://${host}/${instanceid}/wsgi/mapserv_proxy"
"wms_onlineresource" "${web_protocol}://${host}/${instanceid}/wsgi/mapserv_proxy"
"wms_srs" "EPSG:{{srid}}"
"wms_encoding" "UTF-8"
"wms_enable_request" "*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ clean-all:
.PHONY: build
build: $(PRINT_OUTPUT_WAR) \
.build/apache.timestamp \
.build/npm.timestamp \
.build/admin-npm.timestamp \

# Apache

Expand Down Expand Up @@ -192,18 +192,25 @@ endif
$(PYTHON_BIN)/python -m compileall -q geoportal/$(PACKAGE)_geoportal -x geoportal/$(PACKAGE)_geoportal/static.* >/dev/null || true

npm-packages: .config
$(DOCKER_RUN) cp /opt/npm-packages .
$(DOCKER_RUN) cp /opt/c2cgeoportal_admin/npm-packages $@

.build/npm.timestamp: .config npm-packages
geoportal/npm-packages: .config
$(DOCKER_RUN) cp /opt/npm-packages $@

.build/admin-npm.timestamp: npm-packages
rm --force --recursive admin/node_modules
mkdir --parent admin
cat $< | xargs npm install --prefix ./admin
touch $@

.build/geoportal-npm.timestamp: geoportal/npm-packages
rm --force --recursive admin/node_modules
mkdir --parent admin
cat npm-packages | xargs npm install --prefix ./admin
cat $< | xargs npm install --prefix ./geoportal
touch $@

.PHONY: serve-%
serve-%: .build/npm.timestamp
rm -f geoportal/node_modules
ln -s ../admin/node_modules geoportal
serve-%: .build/geoportal-npm.timestamp
(cd geoportal; INTERFACE=$* NODE_ENV=development node_modules/.bin/webpack-dev-server --port=$(DEV_SERVER_PORT) -d --watch --progress \
--public=$(VISIBLE_WEB_HOST):$(VISIBLE_WEB_PORT) --disable-host-check --mode=development)
rm geoportal/node_modules
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ vars:
partitionlimit: 5
routes: &routes
authenticationBaseUrl: base
fulltextsearchUrl: fulltextsearch
gmfLayersUrl: layers_root
gmfRasterUrl: raster
gmfProfileCsvUrl: profile.csv
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.js]
indent_size = 2

[Makefile]
indent_style = tab
Loading