geovisio 2.6.0__py3-none-any.whl → 2.7.1__py3-none-any.whl

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 (62) hide show
  1. geovisio/__init__.py +36 -7
  2. geovisio/admin_cli/cleanup.py +2 -2
  3. geovisio/admin_cli/db.py +1 -4
  4. geovisio/config_app.py +40 -1
  5. geovisio/db_migrations.py +24 -3
  6. geovisio/templates/main.html +13 -13
  7. geovisio/templates/viewer.html +3 -3
  8. geovisio/translations/de/LC_MESSAGES/messages.mo +0 -0
  9. geovisio/translations/de/LC_MESSAGES/messages.po +804 -0
  10. geovisio/translations/el/LC_MESSAGES/messages.mo +0 -0
  11. geovisio/translations/el/LC_MESSAGES/messages.po +685 -0
  12. geovisio/translations/en/LC_MESSAGES/messages.mo +0 -0
  13. geovisio/translations/en/LC_MESSAGES/messages.po +738 -0
  14. geovisio/translations/es/LC_MESSAGES/messages.mo +0 -0
  15. geovisio/translations/es/LC_MESSAGES/messages.po +778 -0
  16. geovisio/translations/fi/LC_MESSAGES/messages.mo +0 -0
  17. geovisio/translations/fi/LC_MESSAGES/messages.po +589 -0
  18. geovisio/translations/fr/LC_MESSAGES/messages.mo +0 -0
  19. geovisio/translations/fr/LC_MESSAGES/messages.po +814 -0
  20. geovisio/translations/hu/LC_MESSAGES/messages.mo +0 -0
  21. geovisio/translations/hu/LC_MESSAGES/messages.po +773 -0
  22. geovisio/translations/ko/LC_MESSAGES/messages.mo +0 -0
  23. geovisio/translations/ko/LC_MESSAGES/messages.po +685 -0
  24. geovisio/translations/messages.pot +694 -0
  25. geovisio/translations/nl/LC_MESSAGES/messages.mo +0 -0
  26. geovisio/translations/nl/LC_MESSAGES/messages.po +602 -0
  27. geovisio/utils/__init__.py +1 -1
  28. geovisio/utils/auth.py +50 -11
  29. geovisio/utils/db.py +65 -0
  30. geovisio/utils/excluded_areas.py +83 -0
  31. geovisio/utils/extent.py +30 -0
  32. geovisio/utils/fields.py +1 -1
  33. geovisio/utils/filesystems.py +0 -1
  34. geovisio/utils/link.py +14 -0
  35. geovisio/utils/params.py +20 -0
  36. geovisio/utils/pictures.py +110 -88
  37. geovisio/utils/reports.py +171 -0
  38. geovisio/utils/sequences.py +262 -126
  39. geovisio/utils/tokens.py +37 -42
  40. geovisio/utils/upload_set.py +642 -0
  41. geovisio/web/auth.py +37 -37
  42. geovisio/web/collections.py +304 -304
  43. geovisio/web/configuration.py +14 -0
  44. geovisio/web/docs.py +276 -15
  45. geovisio/web/excluded_areas.py +377 -0
  46. geovisio/web/items.py +169 -112
  47. geovisio/web/map.py +104 -36
  48. geovisio/web/params.py +69 -26
  49. geovisio/web/pictures.py +14 -31
  50. geovisio/web/reports.py +399 -0
  51. geovisio/web/rss.py +13 -7
  52. geovisio/web/stac.py +129 -134
  53. geovisio/web/tokens.py +98 -109
  54. geovisio/web/upload_set.py +771 -0
  55. geovisio/web/users.py +100 -73
  56. geovisio/web/utils.py +28 -9
  57. geovisio/workers/runner_pictures.py +241 -207
  58. {geovisio-2.6.0.dist-info → geovisio-2.7.1.dist-info}/METADATA +17 -14
  59. geovisio-2.7.1.dist-info/RECORD +70 -0
  60. {geovisio-2.6.0.dist-info → geovisio-2.7.1.dist-info}/WHEEL +1 -1
  61. geovisio-2.6.0.dist-info/RECORD +0 -41
  62. {geovisio-2.6.0.dist-info → geovisio-2.7.1.dist-info}/LICENSE +0 -0
geovisio/web/users.py CHANGED
@@ -1,20 +1,23 @@
1
1
  import flask
2
- from flask import request, current_app
3
- from geovisio.utils import auth
2
+ from flask import request, current_app, url_for
3
+ from flask_babel import gettext as _
4
+ from geovisio.utils import auth, db
4
5
  from geovisio import errors
5
- import psycopg
6
6
  from psycopg.rows import dict_row
7
7
  from psycopg.sql import SQL
8
8
 
9
+ from geovisio.web import stac
10
+ from geovisio.web.utils import get_root_link
11
+
9
12
  bp = flask.Blueprint("user", __name__, url_prefix="/api/users")
10
13
 
11
14
 
12
15
  def _get_user_info(id, name):
13
16
  userMapUrl = (
14
- flask.url_for("map.getUserTile", userId=id, x="111111", y="222222", z="333333", format="mvt", _external=True)
15
- .replace("111111", "{x}")
16
- .replace("222222", "{y}")
17
- .replace("333333", "{z}")
17
+ flask.url_for("map.getUserTile", userId=id, x="11111111", y="22222222", z="33333333", format="mvt", _external=True)
18
+ .replace("11111111", "{x}")
19
+ .replace("22222222", "{y}")
20
+ .replace("33333333", "{z}")
18
21
  )
19
22
  response = {
20
23
  "id": id,
@@ -76,12 +79,11 @@ def getUserInfo(userId):
76
79
  schema:
77
80
  $ref: '#/components/schemas/GeoVisioUser'
78
81
  """
79
- with psycopg.connect(current_app.config["DB_URL"], row_factory=dict_row) as conn, conn.cursor() as cursor:
80
- account = cursor.execute(SQL("SELECT name, id FROM accounts WHERE id = %s"), [userId]).fetchone()
81
- if not account:
82
- raise errors.InvalidAPIUsage("Impossible to find user", status_code=404)
82
+ account = db.fetchone(current_app, SQL("SELECT name, id FROM accounts WHERE id = %s"), [userId], row_factory=dict_row)
83
+ if not account:
84
+ raise errors.InvalidAPIUsage(_("Impossible to find user"), status_code=404)
83
85
 
84
- return _get_user_info(account["id"], account["name"])
86
+ return _get_user_info(account["id"], account["name"])
85
87
 
86
88
 
87
89
  @bp.route("/me/catalog")
@@ -155,14 +157,11 @@ def searchUser():
155
157
  q = request.args.get("q")
156
158
  # for the moment, we can only search by string
157
159
  if not q:
158
- raise errors.InvalidAPIUsage("No search parameter given, you should provide `q=<pattern>` as query parameter", status_code=400)
160
+ raise errors.InvalidAPIUsage(_("No search parameter given, you should provide `q=<pattern>` as query parameter"), status_code=400)
159
161
 
160
162
  limit = request.args.get("limit", default=20, type=int)
161
-
162
- with psycopg.connect(current_app.config["DB_URL"], row_factory=dict_row) as conn, conn.cursor() as cursor:
163
- res = cursor.execute(
164
- SQL(
165
- """
163
+ query = SQL(
164
+ """
166
165
  WITH ranked AS (
167
166
  SELECT name, id, similarity({q}, name) AS similarity from accounts
168
167
  )
@@ -171,29 +170,30 @@ WHERE similarity > 0.1
171
170
  ORDER BY similarity DESC
172
171
  LIMIT {limit};
173
172
  """
174
- ).format(limit=limit, q=q)
175
- ).fetchall()
176
- return {
177
- "features": [
178
- {
179
- "label": r["name"],
180
- "id": r["id"],
181
- "links": [
182
- {
183
- "rel": "user-info",
184
- "type": "application/json",
185
- "href": flask.url_for("user.getUserInfo", userId=r["id"], _external=True),
186
- },
187
- {
188
- "rel": "collection",
189
- "type": "application/json",
190
- "href": flask.url_for("stac_collections.getUserCollection", userId=r["id"], _external=True),
191
- },
192
- ],
193
- }
194
- for r in res
195
- ]
196
- }
173
+ ).format(limit=limit, q=q)
174
+ res = db.fetchall(current_app, query, row_factory=dict_row)
175
+
176
+ return {
177
+ "features": [
178
+ {
179
+ "label": r["name"],
180
+ "id": r["id"],
181
+ "links": [
182
+ {
183
+ "rel": "user-info",
184
+ "type": "application/json",
185
+ "href": flask.url_for("user.getUserInfo", userId=r["id"], _external=True),
186
+ },
187
+ {
188
+ "rel": "collection",
189
+ "type": "application/json",
190
+ "href": flask.url_for("stac_collections.getUserCollection", userId=r["id"], _external=True),
191
+ },
192
+ ],
193
+ }
194
+ for r in res
195
+ ]
196
+ }
197
197
 
198
198
 
199
199
  @bp.route("/")
@@ -213,35 +213,62 @@ def listUsers():
213
213
 
214
214
  # no pagination yet, can be done when needed
215
215
  limit = min(request.args.get("limit", default=1000, type=int), 1000)
216
-
217
- with psycopg.connect(current_app.config["DB_URL"], row_factory=dict_row) as conn, conn.cursor() as cursor:
218
- res = cursor.execute(SQL("""SELECT name, id FROM accounts LIMIT {limit};""").format(limit=limit)).fetchall()
219
- return {
220
- "users": [
221
- {
222
- "name": r["name"],
223
- "id": r["id"],
224
- "links": [
225
- {
226
- "rel": "user-info",
227
- "type": "application/json",
228
- "href": flask.url_for("user.getUserInfo", userId=r["id"], _external=True),
229
- },
230
- {
231
- "rel": "collection",
232
- "type": "application/json",
233
- "href": flask.url_for("stac_collections.getUserCollection", userId=r["id"], _external=True),
234
- },
235
- ],
236
- }
237
- for r in res
238
- ],
239
- "links": [
240
- {
241
- "rel": "user-search",
242
- "type": "application/json",
243
- "href": flask.url_for("user.searchUser", _external=True),
244
- "title": "Search users",
245
- },
246
- ],
247
- }
216
+ query = SQL(
217
+ """SELECT
218
+ a.id, a.name, l.has_seq
219
+ FROM accounts a
220
+ LEFT OUTER JOIN LATERAL (
221
+ SELECT 1 as has_seq
222
+ FROM sequences s
223
+ WHERE s.account_id = a.id
224
+ LIMIT 1
225
+ ) l ON true
226
+ ORDER BY created_at
227
+ LIMIT {limit};"""
228
+ ).format(limit=limit)
229
+ res = db.fetchall(current_app, query, row_factory=dict_row)
230
+ return {
231
+ "stac_version": stac.STAC_VERSION,
232
+ "id": "geovisio:users",
233
+ "title": "users catalog",
234
+ "description": "List of users catalog",
235
+ "type": "Catalog",
236
+ "conformsTo": stac.CONFORMANCE_LIST,
237
+ "users": [
238
+ {
239
+ "name": r["name"],
240
+ "id": r["id"],
241
+ "links": [
242
+ {
243
+ "rel": "user-info",
244
+ "type": "application/json",
245
+ "href": flask.url_for("user.getUserInfo", userId=r["id"], _external=True),
246
+ },
247
+ {
248
+ "rel": "collection",
249
+ "type": "application/json",
250
+ "href": flask.url_for("stac_collections.getUserCollection", userId=r["id"], _external=True),
251
+ },
252
+ ],
253
+ }
254
+ for r in res
255
+ ],
256
+ "links": [
257
+ {
258
+ "rel": "user-search",
259
+ "type": "application/json",
260
+ "href": flask.url_for("user.searchUser", _external=True),
261
+ "title": "Search users",
262
+ },
263
+ get_root_link(),
264
+ ]
265
+ + [
266
+ {
267
+ "rel": "child",
268
+ "title": f'User "{r["name"]}" sequences',
269
+ "href": url_for("stac_collections.getUserCollection", userId=r["id"], _external=True),
270
+ }
271
+ for r in res
272
+ if r["has_seq"]
273
+ ],
274
+ }
geovisio/web/utils.py CHANGED
@@ -2,11 +2,13 @@ import typing
2
2
  from dateutil import tz
3
3
  from datetime import timezone
4
4
  from dateutil.tz import gettz
5
- from typing import Optional
6
- from functools import wraps
7
- import psycopg
8
- from flask import current_app, url_for, Response, make_response
5
+ from functools import wraps, cache
9
6
  from geovisio import errors
7
+ from geovisio.utils import db
8
+ from flask import current_app, url_for
9
+ from flask_babel import gettext as _
10
+ from geovisio import __version__
11
+ import subprocess
10
12
 
11
13
  STAC_VERSION = "1.0.0"
12
14
 
@@ -44,11 +46,10 @@ def accountIdOrDefault(account):
44
46
  # Get default account ID
45
47
  if account is not None:
46
48
  return account.id
47
- with psycopg.connect(current_app.config["DB_URL"]) as conn:
48
- accountId = conn.execute("SELECT id FROM accounts WHERE is_default").fetchone()
49
- if accountId is None:
50
- raise errors.InternalError("No default account defined, please contact your instance administrator")
51
- return str(accountId[0])
49
+ accountId = db.fetchone(current_app, "SELECT id FROM accounts WHERE is_default")
50
+ if accountId is None:
51
+ raise errors.InternalError(_("No default account defined, please contact your instance administrator"))
52
+ return str(accountId[0])
52
53
 
53
54
 
54
55
  def get_license_link():
@@ -85,6 +86,24 @@ def get_viewerpage_url():
85
86
  return url_for("viewer", _external=True)
86
87
 
87
88
 
89
+ @cache
90
+ def get_api_version():
91
+ """
92
+ Retrieve complete API version.
93
+
94
+ Format can be:
95
+ - 2.6.0-99-abcdefgh (release + amount of commits since last tag + commit short SHA) if Git repo is not on a release tag
96
+ - 2.6.0 (release) if Git repo is on release tag (or no Git repo available)
97
+ """
98
+
99
+ if current_app.config.get("API_GIT_VERSION") is not None:
100
+ return current_app.config["API_GIT_VERSION"]
101
+ try:
102
+ return subprocess.check_output(["git", "describe"]).strip().decode("utf-8")
103
+ except Exception:
104
+ return __version__
105
+
106
+
88
107
  def user_dependant_response(flag):
89
108
  """Set if a response is user dependant.
90
109