Skip to content

Commit

Permalink
Merge pull request qgis#56483 from rldhont/server-plugin-filter-onpro…
Browse files Browse the repository at this point in the history
…jectready

Server: onProjectReady method for filter plugin
  • Loading branch information
rldhont authored Feb 23, 2024
2 parents 907d87c + 36f373b commit 55bc8b5
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 11 deletions.
10 changes: 10 additions & 0 deletions python/PyQt6/server/auto_generated/qgsserverfilter.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ parameters, just before entering the main switch for core services.
:return: true if the call must propagate to the subsequent filters, false otherwise

.. versionadded:: 3.24
%End

virtual bool onProjectReady();
%Docstring
Method called when the :py:class:`QgsProject` instance is ready to be used to perform the request,
just before entering the main switch for core services.

:return: true if the call must propagate to the subsequent filters, false otherwise

.. versionadded:: 3.36
%End

virtual bool onResponseComplete();
Expand Down
10 changes: 10 additions & 0 deletions python/server/auto_generated/qgsserverfilter.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ parameters, just before entering the main switch for core services.
:return: true if the call must propagate to the subsequent filters, false otherwise

.. versionadded:: 3.24
%End

virtual bool onProjectReady();
%Docstring
Method called when the :py:class:`QgsProject` instance is ready to be used to perform the request,
just before entering the main switch for core services.

:return: true if the call must propagate to the subsequent filters, false otherwise

.. versionadded:: 3.36
%End

virtual bool onResponseComplete();
Expand Down
17 changes: 15 additions & 2 deletions src/server/qgsfilterresponsedecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ void QgsFilterResponseDecorator::start()
#endif
}

void QgsFilterResponseDecorator::ready()
{
#ifdef HAVE_SERVER_PYTHON_PLUGINS
QgsServerFiltersMap::const_iterator filtersIterator;
for ( filtersIterator = mFilters.constBegin(); filtersIterator != mFilters.constEnd(); ++filtersIterator )
{
if ( ! filtersIterator.value()->onProjectReady() )
{
// stop propagation
return;
}
}
#endif
}

void QgsFilterResponseDecorator::finish()
{
#ifdef HAVE_SERVER_PYTHON_PLUGINS
Expand Down Expand Up @@ -76,5 +91,3 @@ void QgsFilterResponseDecorator::flush()
#endif
mResponse.flush();
}


11 changes: 6 additions & 5 deletions src/server/qgsfilterresponsedecorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ class QgsFilterResponseDecorator: public QgsServerResponse
*/
void start() SIP_THROW( QgsServerException ) SIP_VIRTUALERRORHANDLER( server_exception_handler );

/**
* Call filters projectReady() method
* \since QGIS 3.36
*/
void ready() SIP_THROW( QgsServerException ) SIP_VIRTUALERRORHANDLER( server_exception_handler );

// QgsServerResponse overrides

void setHeader( const QString &key, const QString &value ) override { mResponse.setHeader( key, value ); }
Expand Down Expand Up @@ -85,8 +91,3 @@ class QgsFilterResponseDecorator: public QgsServerResponse
};

#endif





7 changes: 5 additions & 2 deletions src/server/qgsserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &res
sServerInterface->setConfigFilePath( project->fileName() );
}

// Call requestReady() method (if enabled)
// Call requestReady() method (if enabled)
// This may also throw exceptions if there are errors in python plugins code
try
{
Expand Down Expand Up @@ -490,6 +490,10 @@ void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &res
sServerInterface->setConfigFilePath( QString() );
}

// Call projectReady() method (if enabled)
// This may also throw exceptions if there are errors in python plugins code
responseDecorator.ready();

// Note that at this point we still might not have set a valid project.
// There are APIs that work without a project (e.g. the landing page catalog API that
// lists the available projects metadata).
Expand Down Expand Up @@ -617,4 +621,3 @@ void QgsServer::initPython()
}
}
#endif

7 changes: 5 additions & 2 deletions src/server/qgsserverfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ bool QgsServerFilter::onRequestReady()
return true;
}

bool QgsServerFilter::onProjectReady()
{
return true;
}

bool QgsServerFilter::onResponseComplete()
{
Q_NOWARN_DEPRECATED_PUSH
Expand All @@ -71,5 +76,3 @@ bool QgsServerFilter::onSendResponse()
Q_NOWARN_DEPRECATED_POP
return true;
}


10 changes: 10 additions & 0 deletions src/server/qgsserverfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ class SERVER_EXPORT QgsServerFilter
*/
virtual bool onRequestReady();

/**
* Method called when the QgsProject instance is ready to be used to perform the request,
* just before entering the main switch for core services.
*
* \return true if the call must propagate to the subsequent filters, false otherwise
*
* \since QGIS 3.36
*/
virtual bool onProjectReady();

/**
* Method called when the QgsRequestHandler processing has done and
* the response is ready, just after the main switch for core services
Expand Down
87 changes: 87 additions & 0 deletions tests/src/python/test_qgsserver_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ def onRequestReady(self):
request = self.serverInterface().requestHandler()
return self.propagate

def onProjectReady(self):
request = self.serverInterface().requestHandler()
return self.propagate

def onSendResponse(self):
request = self.serverInterface().requestHandler()
request.clearBody()
Expand All @@ -324,12 +328,18 @@ class Filter2(QgsServerFilter):
def __init__(self, iface):
super().__init__(iface)
self.request_ready = False
self.project_ready = False

def onRequestReady(self):
request = self.serverInterface().requestHandler()
self.request_ready = True
return True

def onProjectReady(self):
request = self.serverInterface().requestHandler()
self.project_ready = True
return True

def onSendResponse(self):
request = self.serverInterface().requestHandler()
request.appendBody(b'D')
Expand All @@ -340,6 +350,37 @@ def onResponseComplete(self):
request.appendBody(b'E')
return True

# Methods to manage propagate filter
class Filter3(QgsServerFilter):
def __init__(self, iface, propagate_filter):
super().__init__(iface)
self.propagate_filter = propagate_filter
self.step_to_stop_propagate = None

def onRequestReady(self):
request = self.serverInterface().requestHandler()
if self.step_to_stop_propagate == 'onRequestReady':
self.propagate_filter.propagate = False
return True

def onProjectReady(self):
request = self.serverInterface().requestHandler()
if self.step_to_stop_propagate == 'onProjectReady':
self.propagate_filter.propagate = False
return True

def onSendResponse(self):
request = self.serverInterface().requestHandler()
if self.step_to_stop_propagate == 'onSendResponse':
self.propagate_filter.propagate = False
return True

def onResponseComplete(self):
request = self.serverInterface().requestHandler()
if self.step_to_stop_propagate == 'onResponseComplete':
self.propagate_filter.propagate = False
return True

serverIface = self.server.serverInterface()
serverIface.setFilters({})

Expand All @@ -359,14 +400,60 @@ def onResponseComplete(self):
filter1.propagate = False
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertFalse(filter2.request_ready)
self.assertFalse(filter2.project_ready)
self.assertEqual(body, b'ABC')

# Test with propagation
filter1.propagate = True
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertTrue(filter2.request_ready)
self.assertTrue(filter2.project_ready)
self.assertEqual(body, b'ABDCE')

# Manage propagation
filter3 = Filter3(serverIface, filter1)
serverIface.registerFilter(filter3, 100)

# Stop at onResponseComplete
filter1.propagate = True
filter2.request_ready = False
filter2.project_ready = False
filter3.step_to_stop_propagate = 'onResponseComplete'
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertTrue(filter2.request_ready)
self.assertTrue(filter2.project_ready)
self.assertEqual(body, b'ABDC')

# Stop at onSendResponse
filter1.propagate = True
filter2.request_ready = False
filter2.project_ready = False
filter3.step_to_stop_propagate = 'onSendResponse'
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertTrue(filter2.request_ready)
self.assertTrue(filter2.project_ready)
self.assertEqual(body, b'ABC')

# Stop at onProjectReady
filter1.propagate = True
filter2.request_ready = False
filter2.project_ready = False
filter3.step_to_stop_propagate = 'onProjectReady'
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertTrue(filter2.request_ready)
self.assertFalse(filter2.project_ready)
self.assertEqual(body, b'ABC')

# Stop at onRequestReady
filter1.propagate = True
filter2.request_ready = False
filter2.project_ready = False
filter3.step_to_stop_propagate = 'onRequestReady'
_, body = self._execute_request_project(f'?service={service0.name()}', project=project)
self.assertFalse(filter2.request_ready)
self.assertFalse(filter2.project_ready)
self.assertEqual(body, b'ABC')

serverIface.setFilters({})
reg.unregisterService(service0.name(), service0.version())

Expand Down

0 comments on commit 55bc8b5

Please # to comment.