diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 2512c550a6..9185541790 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -47,7 +47,6 @@ jobs:
strategy:
matrix:
python-version:
- - '3.8'
- '3.9'
- '3.10'
- '3.11'
diff --git a/.github/workflows/daily_check.yaml b/.github/workflows/daily_check.yaml
index c390ba5dee..b253efe889 100644
--- a/.github/workflows/daily_check.yaml
+++ b/.github/workflows/daily_check.yaml
@@ -42,7 +42,6 @@ jobs:
strategy:
matrix:
python-version:
- - python3.8
- python3.9
- python3.10
- python3.11
diff --git a/Dockerfile b/Dockerfile
index da352fa5bd..097322c836 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM python:3.11-buster
+FROM python:3.11-bullseye
ENV DEBIAN_FRONTEND=noninteractive
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 983fb72bda..b1c9f4eb9c 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,8 +1,8 @@
flake8==6.1.0
pyflakes==3.1.0
pycodestyle==2.11.1
-Sphinx==7.1.2
-sphinx_rtd_theme==1.3.0
+Sphinx==7.2.6
+sphinx_rtd_theme==2.0.0
psycopg2==2.9.9
mccabe==0.7.0
c2c.template==2.3.0
diff --git a/dev/database/fed/disclaimer.json.xsl b/dev/database/fed/disclaimer.json.xsl
index 569364b6a1..5f915f3bff 100644
--- a/dev/database/fed/disclaimer.json.xsl
+++ b/dev/database/fed/disclaimer.json.xsl
@@ -14,7 +14,8 @@
"content": {
"": "",
- }
+ },
+ "extract_index":
},
]
diff --git a/dev/database/fed/general_information.json.xsl b/dev/database/fed/general_information.json.xsl
index 27e7ff1f1a..6262a41841 100644
--- a/dev/database/fed/general_information.json.xsl
+++ b/dev/database/fed/general_information.json.xsl
@@ -14,7 +14,8 @@
"content": {
"": "",
- }
+ },
+ "extract_index":
},
]
diff --git a/dev/sample_data/ch.disclaimer.json b/dev/sample_data/ch.disclaimer.json
index 2373cfb601..9d933b2718 100644
--- a/dev/sample_data/ch.disclaimer.json
+++ b/dev/sample_data/ch.disclaimer.json
@@ -14,7 +14,8 @@
"it": "Oltre alle informazioni contenute nel presente estratto, le restrizioni della proprietà possono essere annotate anche nel registro fondiario.",
"rm": "Supplementarmain a las indicaziuns en quest extract pon restricziuns da la proprietad er esser remartgadas en il register funsil.",
"en": "In addition to the information contained in this extract, ownership restrictions may also be cited in the land register."
- }
+ },
+ "extract_index": 10
},
{
"title": {
@@ -28,7 +29,8 @@
"fr": "Le cadastre des sites pollués (CSP) est établi d'après les critères émis par l'Office fédéral de l'environnement OFEV. Il est mis à jour continuellement sur la base des nouvelles connaissances (investigations). Les surfaces des sites indiqués dans le cadastre des sites pollués peuvent ne pas correspondre à la surface effectivement polluée. Cela ne signifie pas que tout terrain non inscrit au cadastre ne soit pas pollué et qu'il soit libre de tout déchet et pollution. Les zones utilisées à des fins de transports publics, militaire et aéronautique sont de la responsabilité de la Confédération.",
"it": "Il catasto dei siti inquinati (CSIN) è stato elaborato sulla base dei criteri definiti dall'Ufficio federale dell'ambiente (UFAM) e viene continuamente aggiornato sulla base delle nuove conoscenze ottenute (p.es. in seguito a indagini). Le superfici riportate nel CSIN possono discostarsi dalla portata dell'inquinamento effettivo. Se un fondo non figura nel CSIN, non esiste alcuna garanzia assoluta che l'area sia libera da inquinamento dovuto a rifiuti o sostanze nocive. I siti sfruttati per finalità ferroviarie, militari o relative all'aviazione civile rientrano nella sfera di competenze della Confederazione.",
"rm": "Il cataster dals lieus contaminads (CLC) è vegnì fatg tenor ils criteris fixads da l'Uffizi federal d'ambient UFAM e vegn actualisà permanentamain sin basa da novas enconuschientschas (p.ex. retschertgas). Las surfatschas inscrittas en il CLC pon divergiar da la dimensiun effectiva da la contaminaziun. Sch'in bain immobigliar n'è betg inditgà en il CLC, na datti nagina garanzia absoluta che l'areal saja liber da mintga contaminaziun che deriva da rument u da substanzas nuschaivlas. Lieus duvrads per il manaschi da la viafier, per il militar e per l'aviatica tutgan tar il champ da cumpetenza da la Confederaziun."
- }
+ },
+ "extract_index": 20
}
]
diff --git a/dev/sample_data/ch.general_information.json b/dev/sample_data/ch.general_information.json
index 5162b13dba..25f38769f5 100644
--- a/dev/sample_data/ch.general_information.json
+++ b/dev/sample_data/ch.general_information.json
@@ -12,7 +12,8 @@
"fr": "Le contenu du cadastre RDPPF est supposé connu. Le canton de ${canton} n'engage pas sa responsabilité sur l'exactitude ou la fiabilité des documents législatifs dans leur version électronique. L'extrait a un caractère informatif et ne crée aucun droit ou obligation. La primauté va aux documents qui ont été légalement adoptés ou publiés. Vous trouverez d'autres informations sur le cadastre RDPPF sous www.cadastre.ch",
"it": "Il contenuto del Catasto RDPP si considera noto. Il Canton ${canton} non può essere ritenuto responsabile per la precisione e l'affidabilità dei documenti legislativi in formato elettronico. L'estratto ha carattere puramente informativo e non è in particolare costitutivo di diritti e obblighi. Sono considerati determinante i documenti approvati o pubblicati passati in giudicato. Ulteriori informazioni relative al Catasto RDPP sono disponibili su www.cadastre.ch",
"rm": "Il cuntegn dal cataster RDPP vegn premess sco enconuschent. Il chantun ${canton} n'è betg responsabel per l'exactadad e per la fidadadad dals documents legislativs electronics. L'extract ha in caracter puramain infurmativ e na motivescha cunzunt nagins dretgs e naginas obligaziuns. Giuridicamain liants èn quels documents ch'èn vegnids deliberads u publitgads cun vigur legala. Ulteriuras infurmaziuns davart il cataster RDPP chattais Vus sut www.cadastre.ch"
- }
+ },
+ "extract_index": 0
}
]
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 5bdea24ad4..217383326f 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -3,101 +3,234 @@
Configuration
=============
-You are looking at a highly configurable piece of software. To get the right understanding of the server it
+You are looking at a highly configurable piece of software. To get a good understanding of the server it
is recommended to read this part carefully.
-Since the swiss confederation's definition and the specification for the `OEREB Data Extract
-`__ is really straight,
-we had very narrow margins to develop the code. Using this pyramid plugin, you will get a running server
-providing the services to satisfy the federal specification. But to get this extract, you need to bind your
-data to this server. And this is basically what you need to configure.
+The specifications of the oereb data model, the web services, the data extracts and the print layout
+by the Swiss Confederation are very precise `OEREB specifications
+`__ . Code development was guided
+by the exact implementation of the specifications and the user requirements. Using this pyramid plugin,
+you will get a running server providing all the services defined by the federal specifications.
+The binding of cantonal and federal data to the server is done by the configuration options.
-This section describes the different possibilities to adapt the application on different data structures or
-even custom data sources. If you are planning to use such modifications, we suggest to check all possible
+This section describes the different possibilities to adapt the application to work with various data structures or
+even custom data sources. If you are planning to implement such modifications, we suggest to check all possible
solutions first, as the necessary effort can vary significantly depending on your specific needs.
+.. _configuration-initial-setup:
+
+Create the inital database setup
+--------------------------------
+
+Out of the box the pyramid_oereb server supports three different topic configurations in the database:
+
+ - the **pyramid_oereb standard model**
+ - the **interlis 2.3 OeREBKRM transfer model**
+ - the **OEREBlex model**
+
+Pyramid_oereb Standard Model
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This schema and table structure is based on the initial topic structure used in the pyramid_oereb
+v1.x versions. It's mainly used for cantonal topics which are not (yet) stored in the interlis 2.3 OeREBKRM-
+Transfer structure and by cantons that do not use OeREB-Lex to manage the legal documents.
+
+Interlis 2.3 OeREBKRM Transfer Model
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+All the federal data sets are provided in this data structure. So this is the schema and table model you
+want to use for all the federal topics unless you want to transform the data to a specific database structure.
+If your cantonal data is also stored based on this model, then you probably want to use this structure
+for all topics to homogenize your database content.
+The `Ili2pg Oereb Data Import Manual `__
+explains how to use the ili2pg tool to create the corresponding schema and how to import the XML data.
+
+
+OEREBlex Topic Model
+^^^^^^^^^^^^^^^^^^^^
+
+This third model is usefull if you maintain your legal documents using the OEREBlex application and you
+have a specific cantonal model for your data. It is similar to the pyramid_oereb standard model, but all
+the document related tables are omitted. Instead the documents are linked by the geolink attribute.
.. _configuration-additional-topics:
-Add additional topics
----------------------
+Add additional standard topics
+------------------------------
+
+If you like to add one or more additional topics based on the *pyramid_oereb standard* database structure
+you can use the internal command below creating an SQL script to establish the topic schema.
-If you only need to add one or more additional cantonal topics and want to use the standard database structure
-for these too, you can run a provided script to generate the required models.
+But before creating any new topic structure you have to add its configuration. Open the configuration file
+(pyramid_oereb.yml) and copy the section from one of the existing **standard** topics which usually
+looks like this:
+
+.. code-block:: yaml
+
+ - code: ch.NE.Baulinien
+ geometry_type: LINESTRING
+ thresholds:
+ length:
+ limit: 1.0
+ area:
+ limit: 1.0
+ language: fr
+ federal: false
+ view_service:
+ layer_index: 1
+ layer_opacity: 0.75
+ source:
+ class: pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource
+ params:
+ db_connection: *main_db_connection
+ # model_factory: pyramid_oereb.contrib.data_sources.standard.models.theme.model_factory_integer_pk
+ # uncomment line above and comment line below to use integer type for primary keys
+ model_factory: pyramid_oereb.contrib.data_sources.standard.models.theme.model_factory_string_pk
+ schema_name: road_building_lines
+ hooks:
+ get_symbol: pyramid_oereb.contrib.data_sources.standard.hook_methods.get_symbol
+ get_symbol_ref: pyramid_oereb.core.hook_methods.get_symbol_ref
+ law_status_lookup:
+ - data_code: inKraft
+ transfer_code: inKraft
+ extract_code: inForce
+ - data_code: AenderungMitVorwirkung
+ transfer_code: AenderungMitVorwirkung
+ extract_code: changeWithPreEffect
+ - data_code: AenderungOhneVorwirkung
+ transfer_code: AenderungOhneVorwirkung
+ extract_code: changeWithoutPreEffect
+ document_types_lookup:
+ - data_code: LegalProvision
+ transfer_code: Rechtsvorschrift
+ extract_code: LegalProvision
+ - data_code: Law
+ transfer_code: GesetzlicheGrundlage
+ extract_code: Law
+ - data_code: Hint
+ transfer_code: Hinweis
+ extract_code: Hint
+
+Apply the necessary modifications/replacements for the new topic. This should at least be the schema name,
+code, geometry type and of course the models property within the source parameters:
+Make sure that this source class is `pyramid_oereb.contrib.data_sources.*standard*.sources.plr.DatabaseSource`
+and not interlis_2_3. - The same goes for the model_factory and the get_symbol element. It should be set to
+*standard*.
+
+Also set the language of the data and if it's a federal (true) or cantonal topic (false). You also want to
+define what lookup codes are for the law_status and document types.
+
+Once the configuration set, run the following command:
.. code-block:: shell
- create_standard_model -c -g -p -k TRUE
+ create_standard_tables -c -T [flag used to skip schema creation]
+ --sql-file= -w [to over-write existing sql instead of append]
-The first parameter is the code of your new topic and has to be defined in camelcase. The geometry type for
-the theme can be one of the following:
+The first parameter ``-c or --configuration=YAML`` is the path to your YAML configuration file.
+By default it's *pyramid_oereb.yml*
- - `POINT`,
- - `LINESTRING`,
- - `POLYGON`
- - `MULTIPOINT`
- - `MULTILINESTRING`
- - `MULTIPOLYGON` or
- - `GEOMETRYCOLLECTION`.
+The second optional parameter ``-s or --section=SECTION`` allows you to specify the section containing
+the configuration part to use. Default is *pyramid_oereb*.
-The geometry collection is only meant for topics that can consist of different geometry types. We **strongly**
-recommend to use it **only if a simple geometry cannot be used** and to put **only one geometry** in each
-record. Do not use it as a bucket for everything! The third parameter defines the output directory in which
-the new file will be created, e.g. a module directory of your application.
+The parameter ``-T or --tables-only`` skips the schema creation and creates only the tables.
-To use strings as primary key type, add the '-k TRUE' parameter. If not supplied, the default primary key type
-of integer will be used instead.
+The option ``--sql-file=SQL_FILE`` generates an SQL file containing the schema and table creation
+commands. *SQL_FILE* should be the name or the absolute path of the file. E.g: my_sql_script.sql
-After creating the models you have to create its configuration. Open the configuration file
-(pyramid_oereb_standard.yml) and copy the section from one of the existing topics which usually looks like
-this:
+If your yaml file uses the c2ctemplate style (starting with vars) you need to add the
+``--c2ctemplate-style`` parameter.
-.. code-block:: yaml
+The option ``-w or --over-write`` allows you to overwrite an existing sql file. Default is append.
- - code: ch.BaulinienNationalstrassen
- geometry_type: LINESTRING
- thresholds:
- length:
- limit: 1.0
- unit: 'm'
- precision: 2
- area:
- limit: 1.0
- unit: 'm2'
- precision: 2
- percentage:
- precision: 1
- text:
- de: Baulinien Nationalstrassen
- language: de
- federal: true
- standard: true
- source:
- class: pyramid_oereb.lib.sources.plr.DatabaseSource
- params:
- db_connection: postgresql://postgres:password@localhost:5432/pyramid_oereb
- models: pyramid_oereb.standard.models.motorways_building_lines
- get_symbol_method: pyramid_oereb.standard.methods.get_symbol
+Now you have set up an empty additional topic in your database and you can proceed with deploying
+your data into it.
+Add additional interlis topics
+------------------------------
-Apply the necessary modifications for the new topic. This should at least be the the name, code and text
-definitions and of course the models property within the source parameters. It should point to the module
-with the generated models of the former step.
+Follow the `Ili2pg Oereb Data Import Manual `__
+to create a new topic schema based on the OeREBKRM Transfer model and about how to import the XML data.
-Now you have set up an empty additional topic and you can continued with deploying your data into it.
+Once the schema is created do not forget to add the corresponding topic configuration in the *pyramid_oereb.yml*
+.. code-block:: yaml
-Add an oereblex topic
+ - code: ch.BaulinienNationalstrassen
+ geometry_type: LINESTRING
+ thresholds:
+ length:
+ limit: 1.0
+ unit: 'm'
+ precision: 2
+ area:
+ limit: 1.0
+ unit: 'm²'
+ precision: 2
+ percentage:
+ precision: 1
+ language: de
+ federal: true
+ view_service:
+ layer_index: 1
+ layer_opacity: 0.75
+ source:
+ class: pyramid_oereb.contrib.data_sources.interlis_2_3.sources.plr.DatabaseSource
+ params:
+ db_connection: *main_db_connection
+ # model_factory: pyramid_oereb.contrib.data_sources.standard.models.theme.model_factory_integer_pk
+ # uncomment line above and comment line below to use integer type for primary keys
+ model_factory: pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_integer_pk
+ schema_name: motorways_building_lines
+ hooks:
+ get_symbol: pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods.get_symbol
+ get_symbol_ref: pyramid_oereb.core.hook_methods.get_symbol_ref
+ law_status_lookup:
+ - data_code: inKraft
+ transfer_code: inKraft
+ extract_code: inForce
+ - data_code: AenderungMitVorwirkung
+ transfer_code: AenderungMitVorwirkung
+ extract_code: changeWithPreEffect
+ - data_code: AenderungOhneVorwirkung
+ transfer_code: AenderungOhneVorwirkung
+ extract_code: changeWithoutPreEffect
+ document_types_lookup:
+ - data_code: Rechtsvorschrift
+ transfer_code: Rechtsvorschrift
+ extract_code: LegalProvision
+ - data_code: GesetzlicheGrundlage
+ transfer_code: GesetzlicheGrundlage
+ extract_code: Law
+ - data_code: Hinweis
+ transfer_code: Hinweis
+ extract_code: Hint
+
+Make sure to set the schema name to the one you defined using ili2pg, also set code, geometry type
+and of course the models property within the source parameters:
+Here the source class is `pyramid_oereb.contrib.data_sources.*interlis_2_3*.sources.plr.DatabaseSource`
+and not standard. - The same goes for the model_factory and the get_symbol element. It should be set to
+*interlis_2_3*.
+
+Also define the language of the data and if it's a federal (true) or cantonal topic (false). You also want to
+define that it is *NOT* the standard structure (false) and what lookup codes are used for the law_status
+and document types.
+
+Add an OEREBLex Topic
---------------------
-If you want to use oereblex for a topic, you can proceed as described in the previous section,
+If you want to use the OEREBlex structure for a topic, you can proceed as described in the previous section,
but using a different script to generate the required models.
.. code-block:: shell
- create_oereblex_model -c -g -p -k TRUE
+ create_oereblex_tables -c -g -p -k TRUE
+
+For all topics
+--------------
+Do not forget to add the availability information in the *pyramid_oereb_main.availability* table to activate (or not)
+the topic for a municipality.
.. _configuration-adapt-models:
@@ -105,10 +238,53 @@ Adapt existing models
---------------------
Another option to modify the standard configuration, is to adapt the existing models to fit another database
-structure. This method is recommended if you are using an existing database supported by GeoAlchemy 2 and
+structure. This method is recommended if you are using an existing database supported by GeoAlchemy2 and
already containing all the necessary data but in a different structure. In this case you should check, if it
is possible to transform the data by extending the existing models with a mapping to fit your structure.
+The easiest example is a simple mapping of table and column names, if you use a different language. Using the
+possibilities of SQLAlchemy, you could extend the existing
+pyramid_oereb.core.models.motorways_building_lines.office
+:ref:`api-pyramid_oereb-core-models-motorways_building_lines-office` like this:
+
+.. code-block:: python
+
+ from pyramid_oereb.lib.standard.models import motorways_building_lines
+
+ class Office(motorways_building_lines.Office):
+ """
+ The bucket to fill in all the offices you need to reference from public law restriction,
+ document, geometry.
+
+ Attributes:
+ id (int): The identifier. This is used in the database only and must not be set manually.
+ If you don't like it - don't care about.
+ name (dict): The multilingual name of the office.
+ office_at_web (str): A web accessible url to a presentation of this office.
+ uid (str): The uid of this office from https
+ line1 (str): The first address line for this office.
+ line2 (str): The second address line for this office.
+ street (str): The streets name of the offices address.
+ number (str): The number on street.
+ postal_code (int): The ZIP-code.
+ city (str): The name of the city.
+ """
+ __table_args__ = {'schema': 'baulinien_nationalstrassen'}
+ __tablename__ = 'amt'
+ id = sa.Column('oid', sa.Integer, primary_key=True)
+ office_at_web = sa.Column('amt_im_web', sa.String, nullable=True)
+ line1 = sa.Column('zeile1', sa.String, nullable=True)
+ line2 = sa.Column('zeile2', sa.String, nullable=True)
+ street = sa.Column('strasse', sa.String, nullable=True)
+ number = sa.Column('hausnr', sa.String, nullable=True)
+ postal_code = sa.Column('plz', sa.Integer, nullable=True)
+ city = sa.Column('ort', sa.String, nullable=True)
+
+ (...)
+
+The only thing, you have to care about, if you want to stay using the standard sources, is to keep the class
+name, the names of the properties and their data types.
+
After extending the models, do not forget to change the models module in the configuration of the topic's
source.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 4b481ced4a..3e7e588b04 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -54,7 +54,10 @@ API). These need to be configured and prepared by the integrator of this package
of documentation.
For the moment we provide an adapter to get the PDF static extract from mapfishprint and
-`oereb_xml_pdf_service `__.
+
+=======
+For the moment we provide an adapter to get the PDF static extract from mapfishprint and
+`xml2pdf `__.
.. image:: ../images/overview.png
:align: center
diff --git a/pyramid_oereb/contrib/data_sources/oereblex/sources/document.py b/pyramid_oereb/contrib/data_sources/oereblex/sources/document.py
index 07e71104f2..4bf1a25084 100644
--- a/pyramid_oereb/contrib/data_sources/oereblex/sources/document.py
+++ b/pyramid_oereb/contrib/data_sources/oereblex/sources/document.py
@@ -199,12 +199,16 @@ def _get_document_records(self, document, language):
raise AssertionError('Missing authority for document #{0}'.format(document.id))
if oereblex_doctype is None:
raise AssertionError('Missing type for document #{0}'.format(document.id))
+ if document.authority_url is None:
+ authority_url = None
+ else:
+ authority_url = {language: document.authority_url}
# Get document type
document_type = Config.get_document_type_by_data_code(self._code, oereblex_doctype)
# Create related office record
- office = OfficeRecord({language: authority}, office_at_web=document.authority_url)
+ office = OfficeRecord({language: authority}, office_at_web=authority_url)
# Get files
records = []
diff --git a/pyramid_oereb/contrib/data_sources/standard/models/main.py b/pyramid_oereb/contrib/data_sources/standard/models/main.py
index c16f145ed7..2d07ae3a81 100644
--- a/pyramid_oereb/contrib/data_sources/standard/models/main.py
+++ b/pyramid_oereb/contrib/data_sources/standard/models/main.py
@@ -219,12 +219,14 @@ class Disclaimer(Base):
id (str): identifier and primary key, used in the database only
title (str): The title which the disclaimer item has.
content (str): The content which the disclaimer item has.
+ extract_index (int): index to sort the disclaimers in the extract
"""
__table_args__ = {'schema': app_schema_name}
__tablename__ = 'disclaimer'
id = Column(String, primary_key=True)
title = Column(JSONType, nullable=False)
content = Column(JSONType, nullable=False)
+ extract_index = Column(Integer, nullable=True)
class LawStatus(Base):
@@ -263,12 +265,14 @@ class GeneralInformation(Base):
id (str): identifier and primary key, used in the database only
title (dict): The title of the general information (multilingual)
content (dict): The actual information (multilingual)
+ extract_index (int): index to sort the items in the extract
"""
__table_args__ = {'schema': app_schema_name}
__tablename__ = 'general_information'
id = Column(String, primary_key=True)
title = Column(JSONType, nullable=False)
content = Column(JSONType, nullable=False)
+ extract_index = Column(Integer, nullable=True)
class ThemeDocument(Base):
diff --git a/pyramid_oereb/contrib/data_sources/standard/sources/disclaimer.py b/pyramid_oereb/contrib/data_sources/standard/sources/disclaimer.py
index 5957c76825..015ee47f1b 100644
--- a/pyramid_oereb/contrib/data_sources/standard/sources/disclaimer.py
+++ b/pyramid_oereb/contrib/data_sources/standard/sources/disclaimer.py
@@ -19,7 +19,8 @@ def read(self):
for result in results:
self.records.append(self._record_class_(
result.title,
- result.content
+ result.content,
+ result.extract_index
))
finally:
session.close()
diff --git a/pyramid_oereb/contrib/data_sources/standard/sources/general_information.py b/pyramid_oereb/contrib/data_sources/standard/sources/general_information.py
index d492103222..8b19bb4b4d 100644
--- a/pyramid_oereb/contrib/data_sources/standard/sources/general_information.py
+++ b/pyramid_oereb/contrib/data_sources/standard/sources/general_information.py
@@ -17,7 +17,8 @@ def read(self):
for result in results:
self.records.append(self._record_class_(
result.title,
- result.content
+ result.content,
+ result.extract_index
))
finally:
session.close()
diff --git a/pyramid_oereb/core/readers/disclaimer.py b/pyramid_oereb/core/readers/disclaimer.py
index 78e79425f4..c7d59a7906 100644
--- a/pyramid_oereb/core/readers/disclaimer.py
+++ b/pyramid_oereb/core/readers/disclaimer.py
@@ -40,4 +40,5 @@ def read(self):
contains all records delivered by the source.
"""
self._source_.read()
+ self._source_.records.sort(key=lambda el: (getattr(el, 'extract_index') or 0))
return self._source_.records
diff --git a/pyramid_oereb/core/readers/general_information.py b/pyramid_oereb/core/readers/general_information.py
index 567282f9bd..20f63bde0f 100644
--- a/pyramid_oereb/core/readers/general_information.py
+++ b/pyramid_oereb/core/readers/general_information.py
@@ -40,4 +40,5 @@ def read(self):
contains all records delivered by the source.
"""
self._source_.read()
+ self._source_.records.sort(key=lambda el: (getattr(el, 'extract_index') or 0))
return self._source_.records
diff --git a/pyramid_oereb/core/records/disclaimer.py b/pyramid_oereb/core/records/disclaimer.py
index 1b6f12ef6b..0214f723f1 100644
--- a/pyramid_oereb/core/records/disclaimer.py
+++ b/pyramid_oereb/core/records/disclaimer.py
@@ -10,7 +10,7 @@ class DisclaimerRecord(object):
title (dict of unicode): The multilingual disclaimer message label
content (dict of unicode): The multilingual disclaimer message.
"""
- def __init__(self, title, content):
+ def __init__(self, title, content, extract_index=None):
"""
Attributes:
title (dict of unicode): The multilingual disclaimer message label
@@ -23,3 +23,4 @@ def __init__(self, title, content):
self.title = title
self.content = content
+ self.extract_index = extract_index
diff --git a/pyramid_oereb/core/records/general_information.py b/pyramid_oereb/core/records/general_information.py
index fec1d926a9..db77525dfe 100644
--- a/pyramid_oereb/core/records/general_information.py
+++ b/pyramid_oereb/core/records/general_information.py
@@ -9,7 +9,7 @@ class GeneralInformationRecord(object):
title (dict of unicode): The title of the information (multilingual)
content (dict of unicode): The actual information (multilingual)
"""
- def __init__(self, title, content):
+ def __init__(self, title, content, extract_index=None):
"""
Args:
title (dict of unicode): The title of the information (multilingual)
@@ -26,7 +26,8 @@ def __init__(self, title, content):
self.title = title
self.content = content
+ self.extract_index = extract_index
def __str__(self):
- return '<{} -- title: {} content: {}>'.format(
- self.__class__.__name__, self.title, self.content)
+ return '<{} -- title: {} content: {} extract index: {}>'.format(
+ self.__class__.__name__, self.title, self.content, self.extract_index)
diff --git a/setup.py b/setup.py
index 710d74b66f..c9d7c4c135 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,6 @@
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
- "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
diff --git a/tests/core/readers/test_disclaimer.py b/tests/core/readers/test_disclaimer.py
index 64bb6b7805..e475526ef1 100644
--- a/tests/core/readers/test_disclaimer.py
+++ b/tests/core/readers/test_disclaimer.py
@@ -27,7 +27,8 @@ def disclaimer_data(dbsession, transact):
'it': u'Il catasto dei siti inquinati (CSIN) è stato elaborato sulla \
base dei criteri definiti dall ...',
'rm': u'',
- }
+ },
+ 'extract_index': 2,
})
]
dbsession.add_all(disclaimers)
@@ -35,6 +36,36 @@ def disclaimer_data(dbsession, transact):
yield disclaimers
+@pytest.fixture(params=[1, 3])
+def multi_disclaimer_data(request, dbsession, transact, disclaimer_data):
+ from pyramid_oereb.contrib.data_sources.standard.models.main import Disclaimer
+ del transact
+ disclaimers = [
+ Disclaimer(**{
+ 'id': 2,
+ 'title': {
+ 'de': u'Haftungsausschluss Kataster der belasteten Standorte V2',
+ 'fr': u'Clause de non-responsabilité du cadastre des sites pollués (CSP) V2',
+ 'it': u'Clausola di esclusione della responsabilità ... V2',
+ 'rm': u''
+ },
+ 'content': {
+ 'de': u'Der Kataster der belasteten Standorte (KbS) \
+ wurde anhand der vom Bundesamt für Umwelt BAFU fe ...',
+ 'fr': u'Le cadastre des sites pollués (CSP) est établi d’après \
+ les critères émis par l’Office fédéral ...',
+ 'it': u'Il catasto dei siti inquinati (CSIN) è stato elaborato sulla \
+ base dei criteri definiti dall ...',
+ 'rm': u'',
+ },
+ 'extract_index': request.param,
+ })
+ ]
+ dbsession.add_all(disclaimers)
+ dbsession.flush()
+ yield disclaimer_data + disclaimers
+
+
@pytest.mark.run(order=2)
def test_init(pyramid_oereb_test_config):
reader = DisclaimerReader(
@@ -58,3 +89,20 @@ def test_read(pyramid_oereb_test_config, disclaimer_data):
assert len(results[0].content) == len(disclaimer_data[0].content)
assert 'du cadastre des sites' in results[0].title['fr']
assert 'Kataster der belasteten Standorte' in results[0].content['de']
+
+
+@pytest.mark.run(order=2)
+def test_sort(pyramid_oereb_test_config, multi_disclaimer_data):
+ reader = DisclaimerReader(
+ pyramid_oereb_test_config.get_disclaimer_config().get('source').get('class'),
+ **pyramid_oereb_test_config.get_disclaimer_config().get('source').get('params')
+ )
+ results = reader.read()
+ assert isinstance(results, list)
+ assert len(results) == len(multi_disclaimer_data)
+ assert isinstance(results[0], DisclaimerRecord)
+ assert len(results[0].title) == len(multi_disclaimer_data[0].title)
+ assert len(results[0].content) == len(multi_disclaimer_data[0].content)
+ assert 'du cadastre des sites' in results[0].title['fr']
+ assert 'Kataster der belasteten Standorte' in results[0].content['de']
+ assert sorted(r.extract_index for r in results) == [r.extract_index for r in results]
diff --git a/tests/core/readers/test_general_information.py b/tests/core/readers/test_general_information.py
new file mode 100644
index 0000000000..3f83c134c5
--- /dev/null
+++ b/tests/core/readers/test_general_information.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+import pytest
+
+from pyramid_oereb.core.sources import Base
+from pyramid_oereb.core.readers.general_information import GeneralInformationReader
+from pyramid_oereb.core.records.general_information import GeneralInformationRecord
+
+
+@pytest.fixture
+def general_information_data(dbsession, transact):
+ from pyramid_oereb.contrib.data_sources.standard.models.main import GeneralInformation
+ del transact
+ general_information = [
+ GeneralInformation(**{
+ 'id': 1,
+ 'title': {
+ 'de': u'GI1',
+ },
+ 'content': {
+ 'de': u'General Information # 1',
+ 'fr': u'Information Generale #1',
+ },
+ 'extract_index': 2,
+ }),
+ GeneralInformation(**{
+ 'id': 2,
+ 'title': {
+ 'de': u'GI2',
+ },
+ 'content': {
+ 'de': u'General Information # 2',
+ 'fr': u'Information Generale #2',
+ },
+ 'extract_index': 3,
+ }),
+ GeneralInformation(**{
+ 'id': 3,
+ 'title': {
+ 'de': u'GI3',
+ },
+ 'content': {
+ 'de': u'General Information # 3',
+ 'fr': u'Information Generale #3',
+ },
+ 'extract_index': 1,
+ })
+ ]
+ dbsession.add_all(general_information)
+ dbsession.flush()
+ yield general_information
+
+
+@pytest.mark.run(order=2)
+def test_init(pyramid_oereb_test_config):
+ reader = GeneralInformationReader(
+ pyramid_oereb_test_config.get_info_config().get('source').get('class'),
+ **pyramid_oereb_test_config.get_info_config().get('source').get('params')
+ )
+ assert isinstance(reader._source_, Base)
+
+
+@pytest.mark.run(order=2)
+def test_read(pyramid_oereb_test_config, general_information_data):
+ reader = GeneralInformationReader(
+ pyramid_oereb_test_config.get_info_config().get('source').get('class'),
+ **pyramid_oereb_test_config.get_info_config().get('source').get('params')
+ )
+ results = reader.read()
+ assert isinstance(results, list)
+ assert len(results) == len(general_information_data)
+ assert isinstance(results[0], GeneralInformationRecord)
+ assert len(results[0].title) == len(general_information_data[0].title)
+ assert len(results[0].content) == len(general_information_data[0].content)
+ assert 'GI3' == results[0].title['de']
+ assert 'Information Generale #1' == results[1].content['fr']
+ assert sorted(r.extract_index for r in results) == [r.extract_index for r in results]
diff --git a/tests/core/sources/test_document_oereblex.py b/tests/core/sources/test_document_oereblex.py
index 02abc3b9a1..ae187c1d78 100644
--- a/tests/core/sources/test_document_oereblex.py
+++ b/tests/core/sources/test_document_oereblex.py
@@ -297,6 +297,9 @@ def test_read_related_notice_as_main(oereblex_test_config):
assert isinstance(document.responsible_office, OfficeRecord)
assert document.responsible_office.name == {'de': '-'}
assert document.responsible_office.office_at_web is None
+ assert source.records[0].responsible_office.office_at_web == {
+ 'de': "http%3A%2F%2Fwww.zihlschlacht-sitterdorf.ch"
+ }
assert document.published_from == datetime.date(1970, 1, 1)
assert document.index == 40