gn2pg_client 1.8.0__tar.gz → 1.9.0.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/PKG-INFO +19 -16
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/README.md +18 -15
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/api.py +34 -28
- gn2pg_client-1.9.0.dev0/gn2pg/app/admin_views.py +58 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/app.py +4 -4
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/config.py +2 -0
- gn2pg_client-1.9.0.dev0/gn2pg/app/models.py +69 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/to_gnsynthese.sql +206 -62
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/download.py +116 -21
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/helpers.py +2 -0
- gn2pg_client-1.8.0/gn2pg/locale/fr_FR/LC_MESSAGES/gn2pg.po~ → gn2pg_client-1.9.0.dev0/gn2pg/locale/fr_FR/LC_MESSAGES/gn2pg.po +80 -74
- gn2pg_client-1.8.0/gn2pg/locale/fr_FR/LC_MESSAGES/gn2pg.po → gn2pg_client-1.9.0.dev0/gn2pg/locale/fr_FR/LC_MESSAGES/gn2pg.po~ +1 -1
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/main.py +0 -32
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/store_postgresql.py +257 -140
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/utils.py +9 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/pyproject.toml +1 -1
- gn2pg_client-1.8.0/gn2pg/app/admin_views.py +0 -41
- gn2pg_client-1.8.0/gn2pg/app/models.py +0 -72
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/LICENSE +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/__init__.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/__init__.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/database.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/env.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/index.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/static/css/custom_flaks_admin.css +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/static/img/src_gn2pg.png +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/templates/admin/master.html +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/templates/index.html +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/utils/__init__.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/utils/admin_views.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/check_conf.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/__init__.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/gn2pgconfig.toml +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/env.py +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/locale/en_US/LC_MESAGES/gn2pg.po +0 -0
- {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: gn2pg_client
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0.dev0
|
|
4
4
|
Summary: Import tool from GeoNature to a PostgreSQL database through Export module API (client side)
|
|
5
5
|
License: AGPL-3.0-or-later
|
|
6
6
|
Keywords: GeoNature,Export,SINP,opendata,biodiversity
|
|
@@ -58,11 +58,11 @@ Widely inspired from [ClientApiVN](https://framagit.org/lpo/Client_API_VN/)
|
|
|
58
58
|
> [!WARNING]
|
|
59
59
|
> The minimum version of the source GeoNature instance required for the incremental update must be a version 2.12.0
|
|
60
60
|
|
|
61
|
-

|
|
62
62
|
|
|
63
63
|
## Project Setup
|
|
64
64
|
|
|
65
|
-
GN2PG Client can be installed by running `pip`. It requires Python 3.
|
|
65
|
+
GN2PG Client can be installed by running `pip`. It requires Python 3.9 or above to run.
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
68
|
pip install gn2pg-client
|
|
@@ -85,7 +85,7 @@ gn2pg_cli --help
|
|
|
85
85
|
This command init a TOML config file within `~/.gn2pg` hidden directory (in user `HOME` directory), named as you want. PLEASE DO NOT SPECIFY PATH!
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
gn2pg_cli --init <myconfigfile>
|
|
88
|
+
gn2pg_cli config --init <myconfigfile>
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
Config file is structured as this. `[[source]]` block can be duplicate as many as needed (one block for each source).
|
|
@@ -149,7 +149,7 @@ data_type = "synthese_with_cd_nomenclature"
|
|
|
149
149
|
To create json tables where datas will be stored, run :
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
gn2pg_cli --json-tables-create <myconfigfile>
|
|
152
|
+
gn2pg_cli db --json-tables-create <myconfigfile>
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
### Full download
|
|
@@ -157,7 +157,7 @@ gn2pg_cli --json-tables-create <myconfigfile>
|
|
|
157
157
|
To download all datas from API, run :
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
gn2pg_cli --full <myconfigfile>
|
|
160
|
+
gn2pg_cli download --full <myconfigfile>
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
### Incremental download
|
|
@@ -165,13 +165,13 @@ gn2pg_cli --full <myconfigfile>
|
|
|
165
165
|
To update data since last download, run :
|
|
166
166
|
|
|
167
167
|
```bash
|
|
168
|
-
gn2pg_cli --update <myconfigfile>
|
|
168
|
+
gn2pg_cli download --update <myconfigfile>
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
To automate the launching of updates, you can write the cron task using the following command, for example every 30 minutes.
|
|
172
172
|
|
|
173
173
|
```cron
|
|
174
|
-
*/30 * * * * /usr/bin/env bash -c "source <path to python environment>/bin/activate && gn2pg_cli --update <myconfigfile>" > /dev/null 2>&1
|
|
174
|
+
*/30 * * * * /usr/bin/env bash -c "source <path to python environment>/bin/activate && gn2pg_cli download --update <myconfigfile>" > /dev/null 2>&1
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
### Debug mode
|
|
@@ -187,7 +187,7 @@ Log files are stored in `$HOME/.gn2pg/log` directory.
|
|
|
187
187
|
Default script to auto populate GeoNature is called "to_gnsynthese".
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
|
-
gn2pg_cli --custom-script to_gnsynthese <myconfigfile>
|
|
190
|
+
gn2pg_cli db --custom-script to_gnsynthese <myconfigfile>
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
> [!TIP]
|
|
@@ -228,16 +228,19 @@ poetry run gn2pg_cli <options>
|
|
|
228
228
|
|
|
229
229
|
## Team
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
<a href="">
|
|
232
|
+
<img height="100px" src="https://auvergne-rhone-alpes.lpo.fr/wp-content/uploads/LPO_AuRA.svg" title="DREAL AuRA">
|
|
233
|
+
</a>
|
|
232
234
|
|
|
233
|
-
|
|
235
|
+
[@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), lead developer
|
|
234
236
|
|
|
235
|
-
|
|
236
|
-
- @mvergez (Natural Solution), contributor
|
|
237
|
-
- @andriacap (Natural Solution), contributor
|
|
238
|
-
- @Adrien-Pajot (Natural Solution), contributor
|
|
237
|
+
---
|
|
239
238
|
|
|
240
|
-
|
|
239
|
+
<a href="https://github.com/lpoaura/GN2PG/graphs/contributors">
|
|
240
|
+
<img src="https://contrib.rocks/image?repo=lpoaura/GN2PG" />
|
|
241
|
+
</a>
|
|
242
|
+
|
|
243
|
+
---
|
|
241
244
|
|
|
242
245
|
With the financial support of the [DREAL Auvergne-Rhône-Alpes](http://www.auvergne-rhone-alpes.developpement-durable.gouv.fr/) and the [Office français de la biodiversité](https://www.ofb.gouv.fr/).
|
|
243
246
|
|
|
@@ -12,11 +12,11 @@ Widely inspired from [ClientApiVN](https://framagit.org/lpo/Client_API_VN/)
|
|
|
12
12
|
> [!WARNING]
|
|
13
13
|
> The minimum version of the source GeoNature instance required for the incremental update must be a version 2.12.0
|
|
14
14
|
|
|
15
|
-

|
|
16
16
|
|
|
17
17
|
## Project Setup
|
|
18
18
|
|
|
19
|
-
GN2PG Client can be installed by running `pip`. It requires Python 3.
|
|
19
|
+
GN2PG Client can be installed by running `pip`. It requires Python 3.9 or above to run.
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
pip install gn2pg-client
|
|
@@ -39,7 +39,7 @@ gn2pg_cli --help
|
|
|
39
39
|
This command init a TOML config file within `~/.gn2pg` hidden directory (in user `HOME` directory), named as you want. PLEASE DO NOT SPECIFY PATH!
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
gn2pg_cli --init <myconfigfile>
|
|
42
|
+
gn2pg_cli config --init <myconfigfile>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Config file is structured as this. `[[source]]` block can be duplicate as many as needed (one block for each source).
|
|
@@ -103,7 +103,7 @@ data_type = "synthese_with_cd_nomenclature"
|
|
|
103
103
|
To create json tables where datas will be stored, run :
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
gn2pg_cli --json-tables-create <myconfigfile>
|
|
106
|
+
gn2pg_cli db --json-tables-create <myconfigfile>
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
### Full download
|
|
@@ -111,7 +111,7 @@ gn2pg_cli --json-tables-create <myconfigfile>
|
|
|
111
111
|
To download all datas from API, run :
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
gn2pg_cli --full <myconfigfile>
|
|
114
|
+
gn2pg_cli download --full <myconfigfile>
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
### Incremental download
|
|
@@ -119,13 +119,13 @@ gn2pg_cli --full <myconfigfile>
|
|
|
119
119
|
To update data since last download, run :
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
gn2pg_cli --update <myconfigfile>
|
|
122
|
+
gn2pg_cli download --update <myconfigfile>
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
To automate the launching of updates, you can write the cron task using the following command, for example every 30 minutes.
|
|
126
126
|
|
|
127
127
|
```cron
|
|
128
|
-
*/30 * * * * /usr/bin/env bash -c "source <path to python environment>/bin/activate && gn2pg_cli --update <myconfigfile>" > /dev/null 2>&1
|
|
128
|
+
*/30 * * * * /usr/bin/env bash -c "source <path to python environment>/bin/activate && gn2pg_cli download --update <myconfigfile>" > /dev/null 2>&1
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
### Debug mode
|
|
@@ -141,7 +141,7 @@ Log files are stored in `$HOME/.gn2pg/log` directory.
|
|
|
141
141
|
Default script to auto populate GeoNature is called "to_gnsynthese".
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
gn2pg_cli --custom-script to_gnsynthese <myconfigfile>
|
|
144
|
+
gn2pg_cli db --custom-script to_gnsynthese <myconfigfile>
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
> [!TIP]
|
|
@@ -182,16 +182,19 @@ poetry run gn2pg_cli <options>
|
|
|
182
182
|
|
|
183
183
|
## Team
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
<a href="">
|
|
186
|
+
<img height="100px" src="https://auvergne-rhone-alpes.lpo.fr/wp-content/uploads/LPO_AuRA.svg" title="DREAL AuRA">
|
|
187
|
+
</a>
|
|
186
188
|
|
|
187
|
-
|
|
189
|
+
[@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), lead developer
|
|
188
190
|
|
|
189
|
-
|
|
190
|
-
- @mvergez (Natural Solution), contributor
|
|
191
|
-
- @andriacap (Natural Solution), contributor
|
|
192
|
-
- @Adrien-Pajot (Natural Solution), contributor
|
|
191
|
+
---
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
<a href="https://github.com/lpoaura/GN2PG/graphs/contributors">
|
|
194
|
+
<img src="https://contrib.rocks/image?repo=lpoaura/GN2PG" />
|
|
195
|
+
</a>
|
|
196
|
+
|
|
197
|
+
---
|
|
195
198
|
|
|
196
199
|
With the financial support of the [DREAL Auvergne-Rhône-Alpes](http://www.auvergne-rhone-alpes.developpement-durable.gouv.fr/) and the [Office français de la biodiversité](https://www.ofb.gouv.fr/).
|
|
197
200
|
|
|
@@ -166,13 +166,16 @@ class BaseAPI:
|
|
|
166
166
|
self,
|
|
167
167
|
params: dict,
|
|
168
168
|
kind: str = "data",
|
|
169
|
-
|
|
169
|
+
pagination_param: str = "offset",
|
|
170
|
+
) -> tuple[Optional[List[str]], int]:
|
|
170
171
|
"""List offset pages to download data, based on API "total_filtered" and "limit" values
|
|
171
172
|
|
|
172
173
|
:param params: Querystrings
|
|
173
174
|
:type params: dict
|
|
174
175
|
:param kind: kind of data, defaults to "data"
|
|
175
176
|
:type kind: str, optional
|
|
177
|
+
:param pagination_param: Pagination parameter key
|
|
178
|
+
:type pagination_param: str, optional
|
|
176
179
|
:return: url page list
|
|
177
180
|
:rtype: Optional[List[str]]
|
|
178
181
|
"""
|
|
@@ -181,41 +184,44 @@ class BaseAPI:
|
|
|
181
184
|
|
|
182
185
|
# Check kind value
|
|
183
186
|
if self._url(kind) is None:
|
|
184
|
-
return None
|
|
187
|
+
return None, 0, None
|
|
185
188
|
|
|
186
189
|
api_url = self._url(kind, params)
|
|
187
|
-
|
|
188
190
|
try:
|
|
189
191
|
response = session.get(url=api_url, params={**params})
|
|
192
|
+
status_code = response.status_code
|
|
193
|
+
if response.status_code == 200:
|
|
194
|
+
resp = response.json()
|
|
195
|
+
total_filtered = (
|
|
196
|
+
resp["total_filtered"] if "total_filtered" in resp else resp["total"]
|
|
197
|
+
)
|
|
198
|
+
limit = resp["limit"]
|
|
199
|
+
total_pages = math.ceil(total_filtered / limit)
|
|
200
|
+
logger.debug(
|
|
201
|
+
_("API %s contains %s data in %s page(s)"),
|
|
202
|
+
api_url,
|
|
203
|
+
total_filtered,
|
|
204
|
+
total_pages,
|
|
205
|
+
)
|
|
206
|
+
if total_filtered > 0:
|
|
207
|
+
page_list = list(
|
|
208
|
+
self._url(
|
|
209
|
+
kind,
|
|
210
|
+
{
|
|
211
|
+
**params,
|
|
212
|
+
**{pagination_param: p + 1 if pagination_param == "page" else p},
|
|
213
|
+
},
|
|
214
|
+
)
|
|
215
|
+
for p in range(total_pages)
|
|
216
|
+
)
|
|
217
|
+
return page_list, total_filtered, status_code
|
|
190
218
|
except RetryError as e:
|
|
219
|
+
last_response = e.response
|
|
220
|
+
status_code = last_response.status_code
|
|
191
221
|
logger.error(_("Export seems to be unavailable : %s"), e)
|
|
192
222
|
raise RetryError from e
|
|
193
223
|
|
|
194
|
-
|
|
195
|
-
_("Defining page_list from %s with status code %s"),
|
|
196
|
-
api_url,
|
|
197
|
-
response.status_code,
|
|
198
|
-
)
|
|
199
|
-
if response.status_code == 200:
|
|
200
|
-
resp = response.json()
|
|
201
|
-
total_filtered = resp["total_filtered"] if "total_filtered" in resp else resp["total"]
|
|
202
|
-
limit = resp["limit"]
|
|
203
|
-
total_pages = math.ceil(total_filtered / limit)
|
|
204
|
-
logger.debug(
|
|
205
|
-
_("API %s contains %s data in %s page(s)"),
|
|
206
|
-
api_url,
|
|
207
|
-
total_filtered,
|
|
208
|
-
total_pages,
|
|
209
|
-
)
|
|
210
|
-
if total_filtered > 0:
|
|
211
|
-
page_list = list(
|
|
212
|
-
self._url(kind, {**params, **{"offset": p}}) for p in range(total_pages)
|
|
213
|
-
)
|
|
214
|
-
return page_list
|
|
215
|
-
|
|
216
|
-
logger.info(_("No data available from %s"), self._config.name)
|
|
217
|
-
|
|
218
|
-
return None
|
|
224
|
+
return None, 0, status_code
|
|
219
225
|
|
|
220
226
|
def get_page(self, page_url: str) -> Optional[dict]:
|
|
221
227
|
"""Get data from one API page
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Admin model views"""
|
|
2
|
+
|
|
3
|
+
from flask_admin.contrib.sqla import ModelView
|
|
4
|
+
|
|
5
|
+
from gn2pg.app.utils.admin_views import add_class_ctn_row_long_text_formatter, json_formatter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ReadOnlyView(ModelView):
|
|
9
|
+
"""Generic read only admin model view"""
|
|
10
|
+
|
|
11
|
+
can_create = False
|
|
12
|
+
can_delete = False
|
|
13
|
+
can_edit = False
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EditOnlyView(ReadOnlyView):
|
|
17
|
+
"""Generic edit only admin model view"""
|
|
18
|
+
|
|
19
|
+
can_edit = True
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ImportView(ReadOnlyView):
|
|
23
|
+
"""Download log view"""
|
|
24
|
+
|
|
25
|
+
column_list = (
|
|
26
|
+
"id",
|
|
27
|
+
"source",
|
|
28
|
+
"controler",
|
|
29
|
+
"xfer_type",
|
|
30
|
+
"xfer_status",
|
|
31
|
+
"xfer_start_ts",
|
|
32
|
+
"xfer_end_ts",
|
|
33
|
+
"api_count_items",
|
|
34
|
+
"api_count_errors",
|
|
35
|
+
"data_count_upserts",
|
|
36
|
+
"data_count_delete",
|
|
37
|
+
"data_count_errors",
|
|
38
|
+
"metadata_count_upserts",
|
|
39
|
+
"metadata_count_errors",
|
|
40
|
+
"xfer_http_status",
|
|
41
|
+
"xfer_filters",
|
|
42
|
+
"comment",
|
|
43
|
+
)
|
|
44
|
+
column_default_sort = ("id", True)
|
|
45
|
+
column_filters = ("source", "xfer_type")
|
|
46
|
+
column_formatters = {
|
|
47
|
+
"xfer_filters": add_class_ctn_row_long_text_formatter,
|
|
48
|
+
"comment": add_class_ctn_row_long_text_formatter,
|
|
49
|
+
}
|
|
50
|
+
can_delete = True
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ErrorView(ReadOnlyView):
|
|
54
|
+
"""Error log view"""
|
|
55
|
+
|
|
56
|
+
column_list = ("source", "uuid", "controler", "last_ts", "item", "error", "import_id")
|
|
57
|
+
column_formatters = {"item": json_formatter, "error": add_class_ctn_row_long_text_formatter}
|
|
58
|
+
column_filters = ["source", "uuid", "controler", "import_id"]
|
|
@@ -5,10 +5,10 @@ from flask_admin import Admin, AdminIndexView
|
|
|
5
5
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
6
6
|
|
|
7
7
|
from gn2pg import _
|
|
8
|
-
from gn2pg.app.admin_views import
|
|
8
|
+
from gn2pg.app.admin_views import ErrorView, ImportView
|
|
9
9
|
from gn2pg.app.config import FlaskConfig
|
|
10
10
|
from gn2pg.app.database import db
|
|
11
|
-
from gn2pg.app.models import
|
|
11
|
+
from gn2pg.app.models import ErrorLog, ImportLog
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def create_app(config=FlaskConfig):
|
|
@@ -18,6 +18,7 @@ def create_app(config=FlaskConfig):
|
|
|
18
18
|
app.config.from_object(config)
|
|
19
19
|
app.config["SQLALCHEMY_DATABASE_URI"] = config.sqlalchemy_database_uri
|
|
20
20
|
app.config["APPLICATION_ROOT"] = config.application_root
|
|
21
|
+
app.config["SECRET_KEY"] = config.secret_key
|
|
21
22
|
app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1)
|
|
22
23
|
db.init_app(app)
|
|
23
24
|
app.config["db"] = db
|
|
@@ -30,8 +31,7 @@ def create_app(config=FlaskConfig):
|
|
|
30
31
|
),
|
|
31
32
|
template_mode="bootstrap4",
|
|
32
33
|
)
|
|
33
|
-
admin.add_view(
|
|
34
|
-
admin.add_view(IncrementView(IncrementLog, db.session, name=_("Incremental downloads")))
|
|
34
|
+
admin.add_view(ImportView(ImportLog, db.session, name=_("Imports")))
|
|
35
35
|
admin.add_view(ErrorView(ErrorLog, db.session, name=_("Error logs")))
|
|
36
36
|
|
|
37
37
|
return app
|
|
@@ -48,6 +48,7 @@ DATABASES = {
|
|
|
48
48
|
DEBUG = settings_config("DEBUG", default=False)
|
|
49
49
|
ENV = settings_config("ENV", default="production")
|
|
50
50
|
APPLICATION_ROOT = settings_config("APPLICATION_ROOT", default="/gn2pg")
|
|
51
|
+
SECRET_KEY = settings_config("SECRET_KEY", default=None)
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class AppConfig:
|
|
@@ -62,6 +63,7 @@ class AppConfig:
|
|
|
62
63
|
def __init__(self):
|
|
63
64
|
self.env = ENV
|
|
64
65
|
self.application_root = APPLICATION_ROOT
|
|
66
|
+
self.secret_key = SECRET_KEY
|
|
65
67
|
self.debug = DEBUG
|
|
66
68
|
self.database = DATABASES["default"]
|
|
67
69
|
self.set_database_uri()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Module providing Models according to database from config file."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
|
4
|
+
from sqlalchemy.sql import func
|
|
5
|
+
|
|
6
|
+
from gn2pg.app.database import db
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ImportLog(db.Model):
|
|
10
|
+
"""Download logs table"""
|
|
11
|
+
|
|
12
|
+
__tablename__ = "import_log"
|
|
13
|
+
__table_args__ = {"schema": "gn2pg_import"}
|
|
14
|
+
id = db.Column(db.Integer, db.Sequence("import_id_seq"), primary_key=True)
|
|
15
|
+
source = db.Column(db.String, nullable=False, index=True)
|
|
16
|
+
controler = db.Column(
|
|
17
|
+
db.String,
|
|
18
|
+
nullable=False,
|
|
19
|
+
)
|
|
20
|
+
xfer_type = db.Column(db.String, index=True)
|
|
21
|
+
xfer_status = db.Column(db.String, index=True)
|
|
22
|
+
xfer_http_status = db.Column(db.String, index=True)
|
|
23
|
+
xfer_filters = db.Column(JSONB, server_default="{}")
|
|
24
|
+
xfer_start_ts = db.Column(
|
|
25
|
+
db.DateTime(timezone=True),
|
|
26
|
+
nullable=False,
|
|
27
|
+
)
|
|
28
|
+
xfer_end_ts = db.Column(
|
|
29
|
+
db.DateTime(timezone=True),
|
|
30
|
+
nullable=True,
|
|
31
|
+
)
|
|
32
|
+
# api_count_data = db.Column(db.Integer, index=True, nullable=False)
|
|
33
|
+
api_count_errors = db.Column(db.Integer, nullable=False)
|
|
34
|
+
data_count_upserts = db.Column(db.Integer, index=True, nullable=False)
|
|
35
|
+
data_count_delete = db.Column(db.Integer, index=True, nullable=False)
|
|
36
|
+
data_count_errors = db.Column(db.Integer, index=True)
|
|
37
|
+
metadata_count_upserts = db.Column(db.Integer, index=True)
|
|
38
|
+
metadata_count_errors = db.Column(db.Integer, index=True)
|
|
39
|
+
comment = db.Column(db.String)
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
return f"<Import_Log {self.id} {self.name}>"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ErrorLog(db.Model):
|
|
46
|
+
"""Error logs table"""
|
|
47
|
+
|
|
48
|
+
__tablename__ = "error_log"
|
|
49
|
+
__table_args__ = {"schema": "gn2pg_import"}
|
|
50
|
+
source = db.Column(db.String, nullable=False, index=True, primary_key=True)
|
|
51
|
+
uuid = db.Column(UUID, nullable=False, index=True)
|
|
52
|
+
controler = db.Column(
|
|
53
|
+
db.String,
|
|
54
|
+
nullable=False,
|
|
55
|
+
)
|
|
56
|
+
last_ts = db.Column(
|
|
57
|
+
db.DateTime(timezone=True),
|
|
58
|
+
server_default=func.now(),
|
|
59
|
+
nullable=False,
|
|
60
|
+
)
|
|
61
|
+
item = db.Column(JSONB)
|
|
62
|
+
error = db.Column(db.String)
|
|
63
|
+
import_id = db.Column(
|
|
64
|
+
db.Integer,
|
|
65
|
+
db.ForeignKey("gn2pg_import.import_log.id", ondelete="CASCADE", onupdate="CASCADE"),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def __repr__(self):
|
|
69
|
+
return f"<error_log {self.name}>"
|