geovisio 2.8.0__py3-none-any.whl → 2.8.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 (36) hide show
  1. geovisio/__init__.py +16 -3
  2. geovisio/config_app.py +0 -1
  3. geovisio/translations/br/LC_MESSAGES/messages.mo +0 -0
  4. geovisio/translations/br/LC_MESSAGES/messages.po +762 -0
  5. geovisio/translations/da/LC_MESSAGES/messages.mo +0 -0
  6. geovisio/translations/da/LC_MESSAGES/messages.po +10 -1
  7. geovisio/translations/de/LC_MESSAGES/messages.mo +0 -0
  8. geovisio/translations/de/LC_MESSAGES/messages.po +10 -1
  9. geovisio/translations/en/LC_MESSAGES/messages.mo +0 -0
  10. geovisio/translations/en/LC_MESSAGES/messages.po +9 -7
  11. geovisio/translations/eo/LC_MESSAGES/messages.mo +0 -0
  12. geovisio/translations/eo/LC_MESSAGES/messages.po +67 -1
  13. geovisio/translations/es/LC_MESSAGES/messages.mo +0 -0
  14. geovisio/translations/es/LC_MESSAGES/messages.po +4 -3
  15. geovisio/translations/fr/LC_MESSAGES/messages.mo +0 -0
  16. geovisio/translations/fr/LC_MESSAGES/messages.po +30 -4
  17. geovisio/translations/hu/LC_MESSAGES/messages.mo +0 -0
  18. geovisio/translations/hu/LC_MESSAGES/messages.po +4 -3
  19. geovisio/translations/it/LC_MESSAGES/messages.mo +0 -0
  20. geovisio/translations/it/LC_MESSAGES/messages.po +10 -1
  21. geovisio/translations/ja/LC_MESSAGES/messages.mo +0 -0
  22. geovisio/translations/ja/LC_MESSAGES/messages.po +242 -154
  23. geovisio/translations/pl/LC_MESSAGES/messages.mo +0 -0
  24. geovisio/translations/pl/LC_MESSAGES/messages.po +4 -3
  25. geovisio/utils/loggers.py +14 -0
  26. geovisio/utils/params.py +7 -4
  27. geovisio/utils/upload_set.py +24 -10
  28. geovisio/utils/website.py +3 -0
  29. geovisio/web/auth.py +3 -2
  30. geovisio/web/docs.py +3 -14
  31. geovisio/web/upload_set.py +98 -10
  32. geovisio/web/users.py +31 -4
  33. {geovisio-2.8.0.dist-info → geovisio-2.8.1.dist-info}/METADATA +4 -3
  34. {geovisio-2.8.0.dist-info → geovisio-2.8.1.dist-info}/RECORD +36 -33
  35. {geovisio-2.8.0.dist-info → geovisio-2.8.1.dist-info}/WHEEL +1 -1
  36. {geovisio-2.8.0.dist-info → geovisio-2.8.1.dist-info/licenses}/LICENSE +0 -0
@@ -8,8 +8,8 @@ msgstr ""
8
8
  "Project-Id-Version: PROJECT VERSION\n"
9
9
  "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
10
10
  "POT-Creation-Date: 2024-10-28 10:15+0100\n"
11
- "PO-Revision-Date: 2024-11-25 10:10+0000\n"
12
- "Last-Translator: Filip Czaplicki <weblatepanoramax722252@starsep.com>\n"
11
+ "PO-Revision-Date: 2025-02-27 12:32+0000\n"
12
+ "Last-Translator: PanierAvide <adrien@pavie.info>\n"
13
13
  "Language-Team: Polish <http://weblate.panoramax.xyz/projects/panoramax/api/"
14
14
  "pl/>\n"
15
15
  "Language: pl\n"
@@ -250,6 +250,7 @@ msgid "Sequence %(c)s is in %(s)s state, its visibility can't be changed for now
250
250
  msgstr ""
251
251
 
252
252
  #: geovisio/web/collections.py:766
253
+ #, fuzzy
253
254
  msgid "Sequence doesn't exists"
254
255
  msgstr "Sekwencja nie istnieje"
255
256
 
@@ -332,7 +333,7 @@ msgid "No more items in this collection (last available rank is %(r)s)"
332
333
  msgstr ""
333
334
 
334
335
  #: geovisio/web/items.py:413
335
- #, python-format
336
+ #, fuzzy, python-format
336
337
  msgid "Picture with id %(p)s does not exists"
337
338
  msgstr "Zdjęcie z id %(p)s nie istnieje"
338
339
 
@@ -0,0 +1,14 @@
1
+ import logging
2
+
3
+
4
+ class LoggingWithExtra(logging.LoggerAdapter):
5
+ """Add some metadata to the log message"""
6
+
7
+ def process(self, msg, kwargs):
8
+ sep = " " if self.extra else ""
9
+ return f"{self.extra if self.extra else ''}{sep}{msg}", kwargs
10
+
11
+
12
+ def getLoggerWithExtra(logger_name, extra):
13
+ """Create a logger with extra information. Those information will be displayed in the log message"""
14
+ return LoggingWithExtra(logging.getLogger(logger_name), extra)
geovisio/utils/params.py CHANGED
@@ -12,9 +12,12 @@ def validation_error(e: ValidationError):
12
12
  }
13
13
  if d["input"]:
14
14
  detail["input"] = d["input"]
15
- if "user_agent" in detail["input"]:
16
- del detail["input"]["user_agent"]
17
- if len(detail["input"]) == 0:
18
- del detail["input"]
15
+ try:
16
+ if "user_agent" in detail["input"]:
17
+ del detail["input"]["user_agent"]
18
+ if len(detail["input"]) == 0:
19
+ del detail["input"]
20
+ except TypeError:
21
+ pass
19
22
  details.append(detail)
20
23
  return {"details": details}
@@ -17,6 +17,8 @@ from flask import current_app
17
17
  from flask_babel import gettext as _
18
18
  from geopic_tag_reader import sequence as geopic_sequence, reader
19
19
 
20
+ from geovisio.utils.loggers import getLoggerWithExtra
21
+
20
22
 
21
23
  class AggregatedStatus(BaseModel):
22
24
  """Aggregated status"""
@@ -435,6 +437,7 @@ def dispatch(upload_set_id: UUID):
435
437
  if not db_upload_set:
436
438
  raise Exception(f"Upload set {upload_set_id} not found")
437
439
 
440
+ logger = getLoggerWithExtra("geovisio.upload_set", {"upload_set_id": str(upload_set_id)})
438
441
  with db.conn(current_app) as conn:
439
442
  with conn.transaction(), conn.cursor(row_factory=dict_row) as cursor:
440
443
 
@@ -493,19 +496,19 @@ WHERE p.upload_set_id = %(upload_set_id)s"""
493
496
  maxDistance=db_upload_set.duplicate_distance, maxRotationAngle=db_upload_set.duplicate_rotation
494
497
  ),
495
498
  sortMethod=db_upload_set.sort_method,
496
- splitParams=geopic_sequence.SplitParams(maxDistance=db_upload_set.split_distance, maxTime=db_upload_set.split_time.seconds),
499
+ splitParams=geopic_sequence.SplitParams(
500
+ maxDistance=db_upload_set.split_distance, maxTime=db_upload_set.split_time.total_seconds()
501
+ ),
497
502
  )
498
503
  reused_sequence = set()
499
504
 
500
505
  pics_to_delete_duplicates = [pics_by_filename[p.filename]["id"] for p in report.duplicate_pictures or []]
501
506
  pics_to_delete = pics_to_delete_duplicates + pics_to_delete_bug
502
507
  if pics_to_delete:
503
- logging.debug(
504
- f"For uploadset '{upload_set_id}', nb duplicate pictures {len(pics_to_delete_duplicates)} {f' and {len(pics_to_delete_bug)} pictures without files' if pics_to_delete_bug else ''}"
505
- )
506
- logging.debug(
507
- f"For uploadset '{upload_set_id}', duplicate pictures {[p.filename for p in report.duplicate_pictures or []]}"
508
+ logger.debug(
509
+ f"nb duplicate pictures {len(pics_to_delete_duplicates)} {f' and {len(pics_to_delete_bug)} pictures without files' if pics_to_delete_bug else ''}"
508
510
  )
511
+ logger.debug(f"duplicate pictures {[p.filename for p in report.duplicate_pictures or []]}")
509
512
 
510
513
  cursor.execute(SQL("CREATE TEMPORARY TABLE tmp_duplicates(picture_id UUID) ON COMMIT DROP"))
511
514
  with cursor.copy("COPY tmp_duplicates(picture_id) FROM stdin;") as copy:
@@ -521,6 +524,8 @@ WHERE p.upload_set_id = %(upload_set_id)s"""
521
524
  cursor.execute(SQL("DELETE FROM pictures WHERE id IN (select picture_id FROM tmp_duplicates)"))
522
525
 
523
526
  number_title = len(report.sequences) > 1
527
+ existing_sequences = set(p["sequence_id"] for p in db_pics if p["sequence_id"])
528
+ new_sequence_ids = set()
524
529
  for i, s in enumerate(report.sequences, start=1):
525
530
  existing_sequence = next(
526
531
  (seq for p in s.pictures if (seq := pics_by_filename[p.filename]["sequence_id"]) not in reused_sequence),
@@ -528,9 +533,7 @@ WHERE p.upload_set_id = %(upload_set_id)s"""
528
533
  )
529
534
  # if some of the pictures were already in a sequence, we should not create a new one
530
535
  if existing_sequence:
531
- logging.info(
532
- f"For uploadset '{upload_set_id}', sequence {existing_sequence} already contains pictures, we will not create a new one"
533
- )
536
+ logger.info(f"sequence {existing_sequence} already contains pictures, we will not create a new one")
534
537
  # we should wipe the sequences_pictures though
535
538
  seq_id = existing_sequence
536
539
  cursor.execute(
@@ -554,6 +557,8 @@ RETURNING id"""
554
557
  ).fetchone()
555
558
  seq_id = seq_id["id"]
556
559
 
560
+ new_sequence_ids.add(seq_id)
561
+
557
562
  with cursor.copy("COPY sequences_pictures(seq_id, pic_id, rank) FROM stdin;") as copy:
558
563
  for i, p in enumerate(s.pictures, 1):
559
564
  copy.write_row(
@@ -562,8 +567,17 @@ RETURNING id"""
562
567
 
563
568
  sequences.add_finalization_job(cursor=cursor, seqId=seq_id)
564
569
 
570
+ # we can delete all the old sequences
571
+ sequences_to_delete = existing_sequences - new_sequence_ids
572
+ if sequences_to_delete:
573
+ logger.debug(f"sequences to delete = {sequences_to_delete} (existing = {existing_sequences}, new = {new_sequence_ids})")
574
+ conn.execute(SQL("DELETE FROM sequences_pictures WHERE seq_id = ANY(%(seq_ids)s)"), {"seq_ids": list(sequences_to_delete)})
575
+ conn.execute(
576
+ SQL("UPDATE sequences SET status = 'deleted' WHERE id = ANY(%(seq_ids)s)"), {"seq_ids": list(sequences_to_delete)}
577
+ )
578
+
565
579
  for s in report.sequences_splits or []:
566
- logging.debug(f"For uploadset '{upload_set_id}', split = {s.prevPic.filename} -> {s.nextPic.filename} : {s.reason}")
580
+ logger.debug(f"split = {s.prevPic.filename} -> {s.nextPic.filename} : {s.reason}")
567
581
  conn.execute(SQL("UPDATE upload_sets SET dispatched = true WHERE id = %(upload_set_id)s"), {"upload_set_id": db_upload_set.id})
568
582
 
569
583
 
geovisio/utils/website.py CHANGED
@@ -37,6 +37,9 @@ class Website:
37
37
  )
38
38
 
39
39
  def _to_url(self, route: str, params: Optional[Dict[str, str]] = None):
40
+ if not self.url:
41
+ return None
42
+
40
43
  base_url = self.url if self.url != WEBSITE_UNDER_SAME_HOST else url_for("index", _external=True)
41
44
 
42
45
  from urllib.parse import urlencode
geovisio/web/auth.py CHANGED
@@ -94,8 +94,9 @@ def auth():
94
94
  if not tos_accepted and current_app.config["API_ENFORCE_TOS_ACCEPTANCE"]:
95
95
  args = {"next_url": next_url} if next_url else None
96
96
  next_url = current_app.config["API_WEBSITE_URL"].tos_validation_page(args)
97
- else:
98
- next_url = next_url or "/"
97
+
98
+ if next_url is None:
99
+ next_url = "/"
99
100
 
100
101
  response = flask.make_response(redirect(next_url))
101
102
 
geovisio/web/docs.py CHANGED
@@ -647,20 +647,9 @@ Available properties are:
647
647
  "GeoVisioUserConfiguration": users.UserConfiguration.model_json_schema(
648
648
  ref_template="#/components/schemas/GeoVisioUserConfiguration/$defs/{model}", mode="serialization"
649
649
  ),
650
- "GeoVisioUser": {
651
- "type": "object",
652
- "properties": {
653
- "id": {"type": "string", "format": "uuid"},
654
- "name": {"type": "string"},
655
- "links": {
656
- "type": "array",
657
- "items": {
658
- "type": "object",
659
- "properties": {"href": {"type": "string"}, "ref": {"type": "string"}, "type": {"type": "string"}},
660
- },
661
- },
662
- },
663
- },
650
+ "GeoVisioUser": users.UserInfo.model_json_schema(
651
+ ref_template="#/components/schemas/GeoVisioUser/$defs/{model}", mode="serialization"
652
+ ),
664
653
  "GeoVisioUserAuth": {
665
654
  "type": "object",
666
655
  "properties": {
@@ -2,7 +2,7 @@ from copy import deepcopy
2
2
  from dataclasses import dataclass
3
3
 
4
4
  import PIL
5
- from geovisio.utils import auth
5
+ from geovisio.utils import auth, model_query
6
6
  from psycopg.rows import class_row, dict_row
7
7
  from psycopg.sql import SQL
8
8
  from flask import current_app, request, Blueprint, url_for
@@ -68,21 +68,32 @@ class UploadSetCreationParameter(BaseModel):
68
68
  model_config = ConfigDict(use_attribute_docstrings=True)
69
69
 
70
70
 
71
- def create_upload_set(params: UploadSetCreationParameter, accountId: UUID) -> UploadSet:
72
- params_as_dict = params.model_dump(exclude_none=True) | {"account_id": accountId}
71
+ class UploadSetUpdateParameter(BaseModel):
72
+ """Parameters used to update an UploadSet"""
73
+
74
+ sort_method: Optional[geopic_sequence.SortMethod] = None
75
+ """Strategy used for sorting your pictures. Either by filename or EXIF time, in ascending or descending order."""
76
+ split_distance: Optional[int] = None
77
+ """Maximum distance between two pictures to be considered in the same sequence (in meters)."""
78
+ split_time: Optional[timedelta] = None
79
+ """Maximum time interval between two pictures to be considered in the same sequence."""
80
+ duplicate_distance: Optional[float] = None
81
+ """Maximum distance between two pictures to be considered as duplicates (in meters)."""
82
+ duplicate_rotation: Optional[int] = None
83
+ """Maximum angle of rotation for two too-close-pictures to be considered as duplicates (in degrees)."""
84
+
85
+ model_config = ConfigDict(use_attribute_docstrings=True, extra="forbid")
73
86
 
74
- fields = [SQL(f) for f in params_as_dict.keys()] # type: ignore (we can ignore psycopg types there as we control those keys since they are the attributes of UploadSetCreationParameter)
75
- values = [SQL(f"%({f})s") for f in params_as_dict.keys()] # type: ignore
76
- for k, v in params_as_dict.items():
77
- if isinstance(v, Dict):
78
- params_as_dict[k] = Jsonb(v) # convert dict to jsonb in database
87
+
88
+ def create_upload_set(params: UploadSetCreationParameter, accountId: UUID) -> UploadSet:
89
+ db_params = model_query.get_db_params_and_values(params, account_id=accountId)
79
90
 
80
91
  db_upload_set = db.fetchone(
81
92
  current_app,
82
93
  SQL("INSERT INTO upload_sets({fields}) VALUES({values}) RETURNING *").format(
83
- fields=SQL(", ").join(fields), values=SQL(", ").join(values)
94
+ fields=db_params.fields(), values=db_params.placeholders()
84
95
  ),
85
- params_as_dict,
96
+ db_params.params_as_dict,
86
97
  row_factory=class_row(UploadSet),
87
98
  )
88
99
 
@@ -92,6 +103,25 @@ def create_upload_set(params: UploadSetCreationParameter, accountId: UUID) -> Up
92
103
  return db_upload_set
93
104
 
94
105
 
106
+ def update_upload_set(upload_set_id: UUID, params: UploadSetUpdateParameter) -> UploadSet:
107
+ db_params = model_query.get_db_params_and_values(params)
108
+
109
+ with db.conn(current_app) as conn, conn.transaction():
110
+ import psycopg
111
+
112
+ cur = psycopg.ClientCursor(conn)
113
+ q = SQL("UPDATE upload_sets SET {fields} WHERE id = %(upload_set_id)s").format(fields=db_params.fields_for_set())
114
+ print(cur.mogrify(q, db_params.params_as_dict | {"upload_set_id": upload_set_id}))
115
+
116
+ with db.execute(
117
+ current_app,
118
+ SQL("UPDATE upload_sets SET {fields} WHERE id = %(upload_set_id)s").format(fields=db_params.fields_for_set()),
119
+ db_params.params_as_dict | {"upload_set_id": upload_set_id},
120
+ ):
121
+ # we get a full uploadset response
122
+ return get_upload_set(upload_set_id)
123
+
124
+
95
125
  @bp.route("/upload_sets", methods=["POST"])
96
126
  @auth.login_required_by_setting("API_FORCE_AUTH_ON_UPLOAD")
97
127
  def postUploadSet(account=None):
@@ -150,6 +180,64 @@ def postUploadSet(account=None):
150
180
  )
151
181
 
152
182
 
183
+ @bp.route("/upload_sets/<uuid:upload_set_id>", methods=["PATCH"])
184
+ @auth.login_required_by_setting("API_FORCE_AUTH_ON_UPLOAD")
185
+ def patchUploadSet(upload_set_id, account=None):
186
+ """Update an existing UploadSet.
187
+
188
+ Note that the upload set will not be dispatched again, so if you changed the dispatch parameters (like split_distance, split_time, duplicate_distance, duplicate_rotation, ...), you need to call the `POST /api/upload_sets/:id/complete` endpoint to dispatch the upload set afterward.
189
+ ---
190
+ tags:
191
+ - Upload
192
+ - UploadSet
193
+ parameters:
194
+ - name: upload_set_id
195
+ in: path
196
+ description: ID of the UploadSet
197
+ required: true
198
+ schema:
199
+ type: string
200
+ requestBody:
201
+ content:
202
+ application/json:
203
+ schema:
204
+ $ref: '#/components/schemas/GeoVisioUploadSet'
205
+ security:
206
+ - bearerToken: []
207
+ - cookieAuth: []
208
+ responses:
209
+ 200:
210
+ description: the UploadSet metadata
211
+ content:
212
+ application/json:
213
+ schema:
214
+ $ref: '#/components/schemas/GeoVisioUploadSet'
215
+ """
216
+
217
+ if request.is_json and request.json is not None:
218
+ try:
219
+ params = UploadSetUpdateParameter(**request.json)
220
+ except ValidationError as ve:
221
+ raise errors.InvalidAPIUsage(_("Impossible to update the UploadSet"), payload=validation_error(ve))
222
+ else:
223
+ raise errors.InvalidAPIUsage(_("Parameter for updating an UploadSet should be a valid JSON"), status_code=415)
224
+
225
+ upload_set = get_simple_upload_set(upload_set_id)
226
+ if upload_set is None:
227
+ raise errors.InvalidAPIUsage(_("UploadSet doesn't exist"), status_code=404)
228
+
229
+ if account and str(upload_set.account_id) != account.id:
230
+ raise errors.InvalidAPIUsage(_("You are not allowed to update this upload set"), status_code=403)
231
+
232
+ if not params.model_fields_set:
233
+ # nothing to update, return the upload set
234
+ upload_set = get_upload_set(upload_set_id)
235
+ else:
236
+ upload_set = update_upload_set(upload_set_id, params)
237
+
238
+ return upload_set.model_dump_json(exclude_none=True), 200, {"Content-Type": "application/json"}
239
+
240
+
153
241
  @bp.route("/upload_sets/<uuid:upload_set_id>", methods=["GET"])
154
242
  def getUploadSet(upload_set_id):
155
243
  """Get an existing UploadSet
geovisio/web/users.py CHANGED
@@ -1,9 +1,9 @@
1
1
  from typing import List, Optional
2
2
  from uuid import UUID
3
3
  import flask
4
- from flask import redirect, request, current_app, session, url_for
4
+ from flask import request, current_app, session, url_for
5
5
  from flask_babel import gettext as _
6
- from pydantic import BaseModel, Field, ValidationError, computed_field
6
+ from pydantic import BaseModel, ConfigDict, ValidationError, computed_field
7
7
  from geovisio.utils import auth, db
8
8
  from geovisio import errors
9
9
  from psycopg.rows import dict_row, class_row
@@ -19,6 +19,21 @@ from geovisio.web.utils import get_root_link
19
19
  bp = flask.Blueprint("user", __name__, url_prefix="/api/users")
20
20
 
21
21
 
22
+ class Permissions(BaseModel):
23
+ """Role and permissions of a user"""
24
+
25
+ role: auth.AccountRole
26
+ """Role of the user"""
27
+ can_check_reports: bool
28
+ """Is account legitimate to read any report ?"""
29
+ can_edit_excluded_areas: bool
30
+ """Is account legitimate to read and edit excluded areas ?"""
31
+ can_edit_pages: bool
32
+ """Is account legitimate to edit web pages ?"""
33
+
34
+ model_config = ConfigDict(use_attribute_docstrings=True, use_enum_values=True)
35
+
36
+
22
37
  class UserInfo(BaseModel):
23
38
  name: str
24
39
  """Name of the user"""
@@ -30,6 +45,11 @@ class UserInfo(BaseModel):
30
45
  tos_accepted: Optional[bool] = None
31
46
  """True means the user has accepted the terms of service (tos). Can only be seen by the user itself"""
32
47
 
48
+ permissions: Optional[Permissions] = None
49
+ """The user role and permissions. Can only be seen by the user itself"""
50
+
51
+ model_config = ConfigDict(use_attribute_docstrings=True)
52
+
33
53
  @computed_field
34
54
  @property
35
55
  def links(self) -> List[Link]:
@@ -55,8 +75,15 @@ def _get_user_info(account: auth.Account):
55
75
  user_info = UserInfo(id=account.id, name=account.name, collaborative_metadata=account.collaborative_metadata)
56
76
  logged_account = auth.get_current_account()
57
77
  if logged_account is not None and account.id == logged_account.id:
58
- # we show the term of service acceptance only if the user is the logged user
59
- user_info.tos_accepted = account.tos_accepted
78
+ # we show the term of service acceptance only if the user is the logged user and if ToS are mandatory
79
+ if flask.current_app.config["API_ENFORCE_TOS_ACCEPTANCE"]:
80
+ user_info.tos_accepted = account.tos_accepted
81
+ user_info.permissions = Permissions(
82
+ role=account.role,
83
+ can_check_reports=account.can_check_reports(),
84
+ can_edit_excluded_areas=account.can_edit_excluded_areas(),
85
+ can_edit_pages=account.can_edit_pages(),
86
+ )
60
87
 
61
88
  return user_info.model_dump(exclude_unset=True), 200, {"Content-Type": "application/json"}
62
89
 
@@ -1,18 +1,19 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: geovisio
3
- Version: 2.8.0
3
+ Version: 2.8.1
4
4
  Summary: GeoVisio API - Main
5
5
  Author-email: Adrien PAVIE <panieravide@riseup.net>, Antoine Desbordes <antoine.desbordes@gmail.com>
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  Classifier: License :: OSI Approved :: MIT License
9
+ License-File: LICENSE
9
10
  Requires-Dist: Flask ~= 2.3
10
11
  Requires-Dist: psycopg[pool] ~= 3.1
11
12
  Requires-Dist: flasgger ~= 0.9.7
12
13
  Requires-Dist: Pillow ~= 9.4
13
14
  Requires-Dist: Flask-Cors ~= 4.0
14
15
  Requires-Dist: fs ~= 2.4
15
- Requires-Dist: fs-s3fs-forked ~= 1.1.3
16
+ Requires-Dist: fs-s3fs-forked ~= 1.1.4
16
17
  Requires-Dist: flask-compress ~= 1.14
17
18
  Requires-Dist: requests ~= 2.31
18
19
  Requires-Dist: yoyo-migrations ~= 8.2
@@ -1,5 +1,5 @@
1
- geovisio/__init__.py,sha256=SPh7-7e0TuxuQNMcF9hDwkg7hW0bJDpbcRnxwu_5DQk,7145
2
- geovisio/config_app.py,sha256=8RlBxn2LcA71o0jcfR5UrVz12ig985MNUgCj54ZydpA,14356
1
+ geovisio/__init__.py,sha256=h7zC88f4S9UjmjGNmSux7v1JqN2Vo05f_8Pv97Zq8Hg,7754
2
+ geovisio/config_app.py,sha256=u44GidJcV4HzCESONi0PsnbfGZqzQ3sxdRXKhpji22o,14198
3
3
  geovisio/db_migrations.py,sha256=9lHkyG_RiCWzrFkfwhkslScUsbCZScN-KVhkXrtnPDo,4560
4
4
  geovisio/errors.py,sha256=uTn-kI7SUl5OPB8Mv3Qqu7Ucp5JvcqWPQFfgLCqsEpI,1376
5
5
  geovisio/admin_cli/__init__.py,sha256=1e0hX771-3iG8eBcNmVvUYyg8qXnpng-9YWvi3MI3Kg,3248
@@ -12,34 +12,36 @@ geovisio/admin_cli/user.py,sha256=4ml2E_aphz3I3NcuUPB2dwe_jXhcE7AGa0R5VTm3_ik,27
12
12
  geovisio/templates/main.html,sha256=VDVQwCZ1mNjH7sH4VOIdn8gM09R9LJZX49SPtA2VEzM,2963
13
13
  geovisio/templates/viewer.html,sha256=JErXdU2ujj4LdMHgQbYNCTfKuYGEXbJTQwBE-K_MNXQ,892
14
14
  geovisio/translations/messages.pot,sha256=SUPAgov3RzwVw0LNOMn2NkTthXfirbBDIQK_2BaZ2FI,19445
15
- geovisio/translations/da/LC_MESSAGES/messages.mo,sha256=zFlDCgA4l-1MamoKMXfFR3diQk67gXM2pEFiZvZwsow,21014
16
- geovisio/translations/da/LC_MESSAGES/messages.po,sha256=Yt1JSEG9e_ljgRvc0u3cknQ5ViU-eJq9XNQ__1Nz-Vs,29084
17
- geovisio/translations/de/LC_MESSAGES/messages.mo,sha256=rO-g7WJC74c9MeuqSAuc3bNZX4G5Vz4O-sHILirjYYk,22590
18
- geovisio/translations/de/LC_MESSAGES/messages.po,sha256=0LcBQjH0LpsHSypXo7kKQKZC0K_yPNyHBuEh5aF7lIk,30776
15
+ geovisio/translations/br/LC_MESSAGES/messages.mo,sha256=FjvUouzaLCBxvVH51A4PVwGGFk6mAepYasnI4v8LcnQ,719
16
+ geovisio/translations/br/LC_MESSAGES/messages.po,sha256=rHkbb3QTngCJxz0WmoBqMl4H-x2bXKYKxdZCEZv2P9w,19434
17
+ geovisio/translations/da/LC_MESSAGES/messages.mo,sha256=46hqJP4gsM3ZK2DG3L47GeC9Q-xFWrY36_OkAJCkuIg,21262
18
+ geovisio/translations/da/LC_MESSAGES/messages.po,sha256=MRmMNc6oQL9R8rvDewHCUhZMSH2TbsfskspCFQzKk2s,29393
19
+ geovisio/translations/de/LC_MESSAGES/messages.mo,sha256=hWb_yaHUHan3tFTyTbnDKJgfnD4wuaeO2nhc24V2ARM,22831
20
+ geovisio/translations/de/LC_MESSAGES/messages.po,sha256=nmlWG_BmcvksfDW9H8d3bTTgIgd-8ucF9lcLg3WB6us,31078
19
21
  geovisio/translations/el/LC_MESSAGES/messages.mo,sha256=vy1jtEG6mLS5sYWPfQIr5U4XsZ21ZzSbsHAJHGQXZSY,433
20
22
  geovisio/translations/el/LC_MESSAGES/messages.po,sha256=gDr-pDCsQGrCXBMBcDwlfsxcGWF1NIEqGrqPcZy65-4,17405
21
- geovisio/translations/en/LC_MESSAGES/messages.mo,sha256=TdE2eywWyvkF0x0qsBPHju3TugQLLqtTk4ZqnAxuJHs,19953
22
- geovisio/translations/en/LC_MESSAGES/messages.po,sha256=Q7j87mLUtyG-wrVvLQXlbTecW8p04a71FnN919UjZN8,27942
23
- geovisio/translations/eo/LC_MESSAGES/messages.mo,sha256=3xtkpuSWl-Wb61cwlB7yK40_JgLMJNB5k1FCFuCfqM8,19330
24
- geovisio/translations/eo/LC_MESSAGES/messages.po,sha256=Gd9n9ZalupqFAlI48y-VQ-XZumTVWnpEOy8-VXnR3Us,26977
25
- geovisio/translations/es/LC_MESSAGES/messages.mo,sha256=ULQDhq4enQyjfAWxDq13BwHBPibg3Yt4ys6XrfQF5tM,19111
26
- geovisio/translations/es/LC_MESSAGES/messages.po,sha256=NoyuXR_2iugWHLTcoUZSNLUSCpt8jMyl0FUD4p7N99w,26775
23
+ geovisio/translations/en/LC_MESSAGES/messages.mo,sha256=KzPxb2olWNvZrUZE9hY0ComHM6t1B2kV5bWvQQ9GUMo,20018
24
+ geovisio/translations/en/LC_MESSAGES/messages.po,sha256=RRfEZ2nZFNWhrbZOPzigy63TVK8cbp8vRikXIj0ibT4,28041
25
+ geovisio/translations/eo/LC_MESSAGES/messages.mo,sha256=67UES-hJwqciW0AiJ2fwcN0K34dBkYNRG2SqVQn3va8,21029
26
+ geovisio/translations/eo/LC_MESSAGES/messages.po,sha256=rzlHUGUoaRkYZY431Y3d7GaAbEcvo9NUL1wSn9Gzapw,29177
27
+ geovisio/translations/es/LC_MESSAGES/messages.mo,sha256=R5JmcfauTrQxIynQNT7asjdLEJC9-VEMXYrcugfBbsY,18950
28
+ geovisio/translations/es/LC_MESSAGES/messages.po,sha256=XzVBY4dISzRcZWw7jMmbGsnDrJvyhzX2L_o9k5B14Hw,26780
27
29
  geovisio/translations/fi/LC_MESSAGES/messages.mo,sha256=6-WCesFiV00MkNM_Wpi7-D51DOZRNg_QOM2sL7-UPhA,626
28
30
  geovisio/translations/fi/LC_MESSAGES/messages.po,sha256=UFT4YCfEazxLij8Ovk2vZqx55e2Yctbf_3xM5KDrXhw,14685
29
- geovisio/translations/fr/LC_MESSAGES/messages.mo,sha256=2kjpCTUbrbAUfFJZ17kR5FAdY_LD5Bh9POzkQvo06-Q,21712
30
- geovisio/translations/fr/LC_MESSAGES/messages.po,sha256=e-PEtl8S4Hjymh9-rv4R45RM3dq-C1M2hdF4CE5Nm6E,29384
31
- geovisio/translations/hu/LC_MESSAGES/messages.mo,sha256=R-0QJl78CNJepsXi8uunlCA-QHhB0_t1Xj6e_EI_NI4,20156
32
- geovisio/translations/hu/LC_MESSAGES/messages.po,sha256=Cs1EaEfVISyIsKxnK-f0gy0ocJdey5o-620mkvW1SAs,27472
33
- geovisio/translations/it/LC_MESSAGES/messages.mo,sha256=jpTyt3Kv19Qu7EHGTzunZyXGMGsg3cg3_EBVxvNmuYA,22260
34
- geovisio/translations/it/LC_MESSAGES/messages.po,sha256=Jw3y5igDkAVvTmJz0sYoopXvOBops5lRqdC6F-j2AXQ,30335
35
- geovisio/translations/ja/LC_MESSAGES/messages.mo,sha256=5t8PzVwGf7ePX3mCQI65pGFOLzF2sQbMPm8svxkxNAE,426
36
- geovisio/translations/ja/LC_MESSAGES/messages.po,sha256=a5S3Lceg47RFSuq7Lcytmu1ni0JGj8nPjWXdF1ZWRVs,18352
31
+ geovisio/translations/fr/LC_MESSAGES/messages.mo,sha256=tvecIWSq7ocm_Q_dd3F1dqZz0GvAWeR685cC7pnQi4g,22297
32
+ geovisio/translations/fr/LC_MESSAGES/messages.po,sha256=unb6P5I9cAMQt5oUr0HhEPmVR3jb7LMnr_e0gAjWwBU,30292
33
+ geovisio/translations/hu/LC_MESSAGES/messages.mo,sha256=0Hb7mv7p1BVM8QqZIYUtF3LRym8Sl9HFWfZAa00TobU,20013
34
+ geovisio/translations/hu/LC_MESSAGES/messages.po,sha256=0nLbjStLDrj7U9mqdIf5gnQ_XzSnhnGQeJ1wLK8l8GM,27494
35
+ geovisio/translations/it/LC_MESSAGES/messages.mo,sha256=a9vR4JuHQY0kwET-OUAD51FgUcCGf68_Cg-P-UOpxRc,22533
36
+ geovisio/translations/it/LC_MESSAGES/messages.po,sha256=kKMX_OabFjzMfYwKA4Gu_n1kND1OKokYwAGs9SSXcj0,30669
37
+ geovisio/translations/ja/LC_MESSAGES/messages.mo,sha256=ZPHJrNdf4bgiNFjxP8W41fkZ2OTJ7Swrqt-Hkh5LfO8,24194
38
+ geovisio/translations/ja/LC_MESSAGES/messages.po,sha256=hE6WOQPaLPjury-bFO3xUJin7bWlcwv0ewSsCpScDdY,32627
37
39
  geovisio/translations/ko/LC_MESSAGES/messages.mo,sha256=eKuQS9zLcJ9s-DzbfR-QK2INBJL10jTIQ1kuSTdJ9Rg,426
38
40
  geovisio/translations/ko/LC_MESSAGES/messages.po,sha256=uq19EZaeRB-obmE1hYnckA8T12JuuU3nXYyKaMR4tiU,17405
39
41
  geovisio/translations/nl/LC_MESSAGES/messages.mo,sha256=aKM90Hp4Eh9vCQba_tlfjEWlhygLXWGq_SVYqBw9IA4,1592
40
42
  geovisio/translations/nl/LC_MESSAGES/messages.po,sha256=m69xfphxpgfPOuUrBK51XrR8UFwqCEBZpnb_5B1mGOU,15302
41
- geovisio/translations/pl/LC_MESSAGES/messages.mo,sha256=0RiGTq49esjtIrBomzeFwG6dWdAlDhJxIOv4AgNjyOQ,10083
42
- geovisio/translations/pl/LC_MESSAGES/messages.po,sha256=JpN6yFqnpyqkMjU3YZLAMr65npQ7AybOLB3ARJoL94g,22192
43
+ geovisio/translations/pl/LC_MESSAGES/messages.mo,sha256=0iFTAhma7jjyl13DCLr2Xr0hgDSN-_fOqcKoYcdDwGE,9912
44
+ geovisio/translations/pl/LC_MESSAGES/messages.po,sha256=e8HW1RKsdkR-aL7peBMuqRUQoqKvzr6Eq0sC1in5XY0,22187
43
45
  geovisio/translations/zh_Hant/LC_MESSAGES/messages.mo,sha256=TmRUyfTGoBpU-2BE-nKjhwdr9r0ikDioVQU-JQ_ih90,431
44
46
  geovisio/translations/zh_Hant/LC_MESSAGES/messages.po,sha256=LnnKlHy8t_54nNsLDBqC1eEPwPx49h1Um9mQj6l9hv0,18357
45
47
  geovisio/utils/__init__.py,sha256=g4SWVoV73cSXjf5-5D9-HmyB5xKmHSuxxOGWnx7W3V0,71
@@ -50,8 +52,9 @@ geovisio/utils/extent.py,sha256=vzOHvbG6lpSNt7KrsaonBOx7Tz46S1J603gLbZvs36g,557
50
52
  geovisio/utils/fields.py,sha256=sNAmrSJ4e-nqm0-LoyO3l4Zynb-Jy8swhwmL3UcDN_o,2129
51
53
  geovisio/utils/filesystems.py,sha256=W_wH7TlvdEux_q4FP0XInxruxlbepFSEpJbPLO9Cnr4,4133
52
54
  geovisio/utils/link.py,sha256=u9x4xJa57L1448neD7uPJuAA76_sFXVE0-9_zPW-bJM,490
55
+ geovisio/utils/loggers.py,sha256=_OrGXME4o5qQz8VBaLxYopHVK0DY0QgzXu6O2W0WBjo,477
53
56
  geovisio/utils/model_query.py,sha256=PtvYCjKVygmicvqqYpCpEKWUIEvwdEG6QMh-JL5E8AQ,2031
54
- geovisio/utils/params.py,sha256=s9kBPHm4gRhMx10SD7mOPdG0tR_n_O-g_rgL8Fife6s,630
57
+ geovisio/utils/params.py,sha256=Yj9-PwC8jxb9LjQZ5K8TERimSsWKwJBHPhUxlzDVMhg,714
55
58
  geovisio/utils/pictures.py,sha256=cDDOABzZaTn98Bg8lYgoMlkTNklS9-y-qB-HXTcJ0YM,23092
56
59
  geovisio/utils/reports.py,sha256=PgU0Td48WJg6XCq043he8Jif3WCA9nOTaGE0Yovo3h0,5626
57
60
  geovisio/utils/semantics.py,sha256=bsPo4n0R0_pU5NdL7-dkx-bMYPhtyVq85z4nHNLptto,4572
@@ -59,14 +62,14 @@ geovisio/utils/sentry.py,sha256=Dw0rW2sNFbcpGojzpa-vjtJ5S7BH_XhsqfuGYBjHCG0,3759
59
62
  geovisio/utils/sequences.py,sha256=S3OaMozzk9viYJMgHyzGYP1hZFsYjF8Ez2hXFTIBimI,25307
60
63
  geovisio/utils/time.py,sha256=-hOs7FSx-8eiGmMQtTOrCoF8d_yMlj2306vfxJftEr8,642
61
64
  geovisio/utils/tokens.py,sha256=tkihnnXqgQeIME_d12tC8PVrPN90A0i9k6UPEbgZ9TQ,3047
62
- geovisio/utils/upload_set.py,sha256=P27ABINmMgNaFGMqd6rLLbeaOSddTz7Tchs2ByKDHeM,26478
63
- geovisio/utils/website.py,sha256=wQosLHD-7_ONReJijKCjGUawKz1eCyBLWwkSWxd6ei8,1909
65
+ geovisio/utils/upload_set.py,sha256=OVChyYFVd6maXcoMoiT-tA1n6tPIezTEJiRdipw_hIw,27247
66
+ geovisio/utils/website.py,sha256=812_leydUaI_gPZAnkVizGH1ZJqJkoAE1usFCrRNHCI,1959
64
67
  geovisio/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
68
  geovisio/web/annotations.py,sha256=TdivDOcVh83HRkBXBTxFD7J-VbZ1gnVesPfTNY-3uW4,653
66
- geovisio/web/auth.py,sha256=-msYF5q2OUsa3rYH7H0vjclt6JEaPy9CHzjWmCCwZUU,7139
69
+ geovisio/web/auth.py,sha256=d0g3EweC74_OOvD9fxb71M-VuQLD_BdlOcKtpwH4t5o,7143
67
70
  geovisio/web/collections.py,sha256=pt181nK3bTa1UYn9qpi3RBGH5h5I8VKMOb_Kfa-c-EU,46470
68
71
  geovisio/web/configuration.py,sha256=tWZYxOoqI2MQwmuHk1I9J2DKzDqpLBVmWRDSsx18U7E,2177
69
- geovisio/web/docs.py,sha256=RxMtyH_Urcr0YWPTZz1epMKr-iHRwRXBdRzgdhZzaWU,56054
72
+ geovisio/web/docs.py,sha256=UgiX_uXAdzjk08Q5Slp40-ayfhhfaHMZn88SU8IBQAg,55660
70
73
  geovisio/web/excluded_areas.py,sha256=5BNSZ0UqgFMtgvgrJ73eYGJXPJRnV-mGEs36WDRRxTk,13024
71
74
  geovisio/web/items.py,sha256=1a_O5tes2NL4DHqDWsgJn_PQQYx4Ft6v4t7ibzkgtdw,61357
72
75
  geovisio/web/map.py,sha256=DaigXevz4lL7WGjPFCsKbXvjdDevFj9gpH0-22JsJOI,25328
@@ -78,12 +81,12 @@ geovisio/web/reports.py,sha256=8v9a4PMM9RsvSGadZEN2o5PTKG_TohjyMMEBfFeY13E,14123
78
81
  geovisio/web/rss.py,sha256=NLUd2Or92tcKRaGUHAze6QMLWczHyzag9ybOzrA8djE,2962
79
82
  geovisio/web/stac.py,sha256=1uoSUOgCxOdH4UQuUvt-0xJaPLtPcAD54WvQg0lvxwM,14850
80
83
  geovisio/web/tokens.py,sha256=l7CAM0FQ6qAcoUhtIRysKc9Gndlji_wOMpkXLsPP1pI,9599
81
- geovisio/web/upload_set.py,sha256=IkZrSosJ6LenqEsNFx4BOULZCUrcl8yIz_sO4B5xyeM,30671
82
- geovisio/web/users.py,sha256=CB5fJxZyIUDtlQ-BKfV4zZtnlSGqgZehsMk2rlVTvHk,13038
84
+ geovisio/web/upload_set.py,sha256=lFryohoh40UaGoHPL-RV7ypWrYlOwYlW6Y5m65dkEyA,34251
85
+ geovisio/web/users.py,sha256=PeB2hcyyLvNDi98iNl8P4wr3X4r3Yz6FVP8Yx_U6Nac,14054
83
86
  geovisio/web/utils.py,sha256=kudTbV4Tgtkbd4oUWFTFpyWNINpxAa-VQNbxYEiR6pM,3640
84
87
  geovisio/workers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
88
  geovisio/workers/runner_pictures.py,sha256=Y4x345tp0Y3RAFnoYpcDhyg6dJS1OYx79XGGDIttcps,22898
86
- geovisio-2.8.0.dist-info/LICENSE,sha256=iRFSz7MJ7_j4hh3hvIgzNbS2buy5NMva8lulaixd3IE,1069
87
- geovisio-2.8.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
88
- geovisio-2.8.0.dist-info/METADATA,sha256=xWj0uWtGYpQQ_Fmcp6XPd6MslTkeQHlVybq_7zSEjgs,4299
89
- geovisio-2.8.0.dist-info/RECORD,,
89
+ geovisio-2.8.1.dist-info/licenses/LICENSE,sha256=iRFSz7MJ7_j4hh3hvIgzNbS2buy5NMva8lulaixd3IE,1069
90
+ geovisio-2.8.1.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
91
+ geovisio-2.8.1.dist-info/METADATA,sha256=r3Tlh_xpB_BVY27DjaV8W6UVjz__db7Z55zWHj536zQ,4321
92
+ geovisio-2.8.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.10.1
2
+ Generator: flit 3.11.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any