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.
Files changed (36) hide show
  1. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/PKG-INFO +19 -16
  2. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/README.md +18 -15
  3. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/api.py +34 -28
  4. gn2pg_client-1.9.0.dev0/gn2pg/app/admin_views.py +58 -0
  5. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/app.py +4 -4
  6. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/config.py +2 -0
  7. gn2pg_client-1.9.0.dev0/gn2pg/app/models.py +69 -0
  8. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/to_gnsynthese.sql +206 -62
  9. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/download.py +116 -21
  10. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/helpers.py +2 -0
  11. 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
  12. 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
  13. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/main.py +0 -32
  14. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/store_postgresql.py +257 -140
  15. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/utils.py +9 -0
  16. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/pyproject.toml +1 -1
  17. gn2pg_client-1.8.0/gn2pg/app/admin_views.py +0 -41
  18. gn2pg_client-1.8.0/gn2pg/app/models.py +0 -72
  19. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/LICENSE +0 -0
  20. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/__init__.py +0 -0
  21. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/__init__.py +0 -0
  22. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/database.py +0 -0
  23. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/env.py +0 -0
  24. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/index.py +0 -0
  25. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/static/css/custom_flaks_admin.css +0 -0
  26. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/static/img/src_gn2pg.png +0 -0
  27. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/templates/admin/master.html +0 -0
  28. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/templates/index.html +0 -0
  29. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/utils/__init__.py +0 -0
  30. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/app/utils/admin_views.py +0 -0
  31. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/check_conf.py +0 -0
  32. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/__init__.py +0 -0
  33. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/data/gn2pgconfig.toml +0 -0
  34. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/env.py +0 -0
  35. {gn2pg_client-1.8.0 → gn2pg_client-1.9.0.dev0}/gn2pg/locale/en_US/LC_MESAGES/gn2pg.po +0 -0
  36. {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.8.0
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
- ![Project logo](./docs/source/_static/src_gn2pg.png)
61
+ ![Project logo](./docs/_static/src_gn2pg.png)
62
62
 
63
63
  ## Project Setup
64
64
 
65
- GN2PG Client can be installed by running `pip`. It requires Python 3.7.4 or above to run.
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
- - [@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), main developer
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
- ![Logo LPOAuRA](https://raw.githubusercontent.com/lpoaura/biodivsport-widget/master/images/LPO_AuRA_l250px.png)
235
+ [@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), lead developer
234
236
 
235
- - @ophdlv (Natural Solution), contributor
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
- ![Project logo](./docs/source/_static/src_gn2pg.png)
15
+ ![Project logo](./docs/_static/src_gn2pg.png)
16
16
 
17
17
  ## Project Setup
18
18
 
19
- GN2PG Client can be installed by running `pip`. It requires Python 3.7.4 or above to run.
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
- - [@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), main developer
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
- ![Logo LPOAuRA](https://raw.githubusercontent.com/lpoaura/biodivsport-widget/master/images/LPO_AuRA_l250px.png)
189
+ [@lpofredc](https://github.com/lpofredc/) ([LPO Auvergne-Rhône-Alpes](https://github.com/lpoaura/)), lead developer
188
190
 
189
- - @ophdlv (Natural Solution), contributor
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
- ) -> Optional[List[str]]:
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
- logger.debug(
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 DownloadView, ErrorView, IncrementView
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 DownloadLog, ErrorLog, IncrementLog
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(DownloadView(DownloadLog, db.session, name=_("Full downloads")))
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}>"