geovisio 2.7.1__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.
- geovisio/__init__.py +25 -4
- geovisio/admin_cli/__init__.py +3 -1
- geovisio/admin_cli/user.py +75 -0
- geovisio/config_app.py +86 -4
- geovisio/templates/main.html +2 -2
- geovisio/templates/viewer.html +3 -3
- geovisio/translations/br/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/br/LC_MESSAGES/messages.po +762 -0
- geovisio/translations/da/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/da/LC_MESSAGES/messages.po +859 -0
- geovisio/translations/de/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/de/LC_MESSAGES/messages.po +106 -1
- geovisio/translations/el/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/en/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/en/LC_MESSAGES/messages.po +218 -133
- geovisio/translations/eo/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/eo/LC_MESSAGES/messages.po +856 -0
- geovisio/translations/es/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/es/LC_MESSAGES/messages.po +4 -3
- geovisio/translations/fi/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/fr/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/fr/LC_MESSAGES/messages.po +66 -3
- geovisio/translations/hu/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/hu/LC_MESSAGES/messages.po +4 -3
- geovisio/translations/it/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/it/LC_MESSAGES/messages.po +884 -0
- geovisio/translations/ja/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/ja/LC_MESSAGES/messages.po +807 -0
- geovisio/translations/ko/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/messages.pot +191 -122
- geovisio/translations/nl/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/pl/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/pl/LC_MESSAGES/messages.po +728 -0
- geovisio/translations/zh_Hant/LC_MESSAGES/messages.mo +0 -0
- geovisio/translations/zh_Hant/LC_MESSAGES/messages.po +719 -0
- geovisio/utils/auth.py +80 -8
- geovisio/utils/link.py +3 -2
- geovisio/utils/loggers.py +14 -0
- geovisio/utils/model_query.py +55 -0
- geovisio/utils/params.py +7 -4
- geovisio/utils/pictures.py +12 -43
- geovisio/utils/semantics.py +120 -0
- geovisio/utils/sequences.py +10 -1
- geovisio/utils/tokens.py +5 -3
- geovisio/utils/upload_set.py +71 -22
- geovisio/utils/website.py +53 -0
- geovisio/web/annotations.py +17 -0
- geovisio/web/auth.py +11 -6
- geovisio/web/collections.py +217 -61
- geovisio/web/configuration.py +17 -1
- geovisio/web/docs.py +67 -67
- geovisio/web/items.py +220 -96
- geovisio/web/map.py +48 -18
- geovisio/web/pages.py +240 -0
- geovisio/web/params.py +17 -0
- geovisio/web/prepare.py +165 -0
- geovisio/web/stac.py +17 -4
- geovisio/web/tokens.py +14 -4
- geovisio/web/upload_set.py +108 -14
- geovisio/web/users.py +203 -44
- geovisio/workers/runner_pictures.py +61 -22
- {geovisio-2.7.1.dist-info → geovisio-2.8.1.dist-info}/METADATA +8 -6
- geovisio-2.8.1.dist-info/RECORD +92 -0
- {geovisio-2.7.1.dist-info → geovisio-2.8.1.dist-info}/WHEEL +1 -1
- geovisio-2.7.1.dist-info/RECORD +0 -70
- {geovisio-2.7.1.dist-info → geovisio-2.8.1.dist-info/licenses}/LICENSE +0 -0
geovisio/__init__.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""GeoVisio API - Main"""
|
|
2
2
|
|
|
3
|
-
__version__ = "2.
|
|
3
|
+
__version__ = "2.8.1"
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from flask import Flask, jsonify, stream_template, send_from_directory, redirect, request
|
|
6
|
+
from flask import Flask, jsonify, stream_template, send_from_directory, redirect, request, url_for
|
|
7
7
|
from flask.cli import with_appcontext
|
|
8
8
|
from flask_cors import CORS
|
|
9
9
|
from flask_compress import Compress
|
|
@@ -28,6 +28,9 @@ from geovisio.web import (
|
|
|
28
28
|
upload_set,
|
|
29
29
|
reports,
|
|
30
30
|
excluded_areas,
|
|
31
|
+
prepare,
|
|
32
|
+
pages,
|
|
33
|
+
annotations,
|
|
31
34
|
)
|
|
32
35
|
from geovisio.workers import runner_pictures
|
|
33
36
|
|
|
@@ -73,12 +76,12 @@ def create_app(test_config=None, app=None):
|
|
|
73
76
|
if app is None:
|
|
74
77
|
app = Flask(__name__, instance_relative_config=True)
|
|
75
78
|
CORS(app, supports_credentials=True)
|
|
76
|
-
Compress(app)
|
|
77
79
|
|
|
78
80
|
config_app.read_config(app, test_config)
|
|
79
81
|
sentry.init(app)
|
|
80
82
|
db.create_db_pool(app)
|
|
81
83
|
Babel(app, locale_selector=get_locale)
|
|
84
|
+
Compress(app)
|
|
82
85
|
|
|
83
86
|
# Prepare filesystem
|
|
84
87
|
createDirNoFailure(app.instance_path)
|
|
@@ -88,6 +91,8 @@ def create_app(test_config=None, app=None):
|
|
|
88
91
|
if app.config.get("DB_CHECK_SCHEMA"):
|
|
89
92
|
db_migrations.update_db_schema(app.config["DB_URL"])
|
|
90
93
|
|
|
94
|
+
config_app.persist_config(app)
|
|
95
|
+
|
|
91
96
|
if app.config.get("OAUTH_PROVIDER"):
|
|
92
97
|
utils.auth.make_auth(app)
|
|
93
98
|
app.register_blueprint(auth.bp)
|
|
@@ -101,7 +106,9 @@ def create_app(test_config=None, app=None):
|
|
|
101
106
|
# https://flask.palletsprojects.com/en/2.2.x/deploying/proxy_fix/
|
|
102
107
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
103
108
|
|
|
104
|
-
app.wsgi_app = ProxyFix(
|
|
109
|
+
app.wsgi_app = ProxyFix(
|
|
110
|
+
app.wsgi_app, x_for=nb_proxies, x_proto=nb_proxies, x_host=nb_proxies, x_prefix=nb_proxies, x_port=nb_proxies
|
|
111
|
+
)
|
|
105
112
|
|
|
106
113
|
# store the background processor in the app context
|
|
107
114
|
app.background_processor = runner_pictures.PictureBackgroundProcessor(app)
|
|
@@ -121,6 +128,9 @@ def create_app(test_config=None, app=None):
|
|
|
121
128
|
app.register_blueprint(upload_set.bp)
|
|
122
129
|
app.register_blueprint(reports.bp)
|
|
123
130
|
app.register_blueprint(excluded_areas.bp)
|
|
131
|
+
app.register_blueprint(prepare.bp)
|
|
132
|
+
app.register_blueprint(pages.bp)
|
|
133
|
+
app.register_blueprint(annotations.bp)
|
|
124
134
|
|
|
125
135
|
# Register CLI comands
|
|
126
136
|
app.register_blueprint(admin_cli.bp, cli_group=None)
|
|
@@ -177,6 +187,17 @@ def create_app(test_config=None, app=None):
|
|
|
177
187
|
def favicon():
|
|
178
188
|
return redirect("/static/img/favicon.ico")
|
|
179
189
|
|
|
190
|
+
@app.route("/api/debug_headers")
|
|
191
|
+
def debug_headers():
|
|
192
|
+
"""Endpoint handy when setting a new instance to check if all the headers are set correctly,
|
|
193
|
+
and especially the X-Forwarded-* header that needs to be set by the proxies in order for the API to correctly build internal urls.
|
|
194
|
+
|
|
195
|
+
The headers are only printed to the console, so it's only for the instance administrator that has access to those logs.
|
|
196
|
+
"""
|
|
197
|
+
logging.info(request.headers)
|
|
198
|
+
|
|
199
|
+
return jsonify({"test_url": url_for("index", _external=True)}), 200
|
|
200
|
+
|
|
180
201
|
# Errors
|
|
181
202
|
@app.errorhandler(errors.InvalidAPIUsage)
|
|
182
203
|
def invalid_api_usage(e):
|
geovisio/admin_cli/__init__.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from flask import Blueprint
|
|
2
|
+
from flask import cli
|
|
2
3
|
from flask.cli import with_appcontext
|
|
3
4
|
import click
|
|
4
5
|
import logging
|
|
5
|
-
from . import default_account_tokens, reorder_sequences, sequence_heading, cleanup, db
|
|
6
|
+
from . import default_account_tokens, reorder_sequences, sequence_heading, cleanup, db, user
|
|
6
7
|
|
|
7
8
|
bp = Blueprint("cli", __name__)
|
|
8
9
|
|
|
9
10
|
bp.register_blueprint(default_account_tokens.bp, cli_group="default-account-tokens")
|
|
11
|
+
bp.register_blueprint(user.bp, cli_group=None)
|
|
10
12
|
bp.register_blueprint(db.bp, cli_group="db")
|
|
11
13
|
|
|
12
14
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from uuid import UUID
|
|
2
|
+
from attr import dataclass
|
|
3
|
+
import click
|
|
4
|
+
from flask import Blueprint, current_app
|
|
5
|
+
from flask.cli import with_appcontext
|
|
6
|
+
from geovisio.utils import db
|
|
7
|
+
from geovisio.utils.auth import AccountRole
|
|
8
|
+
from psycopg.rows import dict_row
|
|
9
|
+
|
|
10
|
+
bp = Blueprint("user", __name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Account:
|
|
15
|
+
id: UUID
|
|
16
|
+
name: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@bp.cli.command("user")
|
|
20
|
+
@click.argument("account_id_or_name")
|
|
21
|
+
@click.option("--set-role", required=True, help="Role you want to give to the account. Must be one of: admin or user")
|
|
22
|
+
@click.option("--create", is_flag=True, show_default=True, default=False, help="If provided, create the account if it does not exist")
|
|
23
|
+
@with_appcontext
|
|
24
|
+
def update_user(account_id_or_name, set_role=None, create=False):
|
|
25
|
+
"""
|
|
26
|
+
Update some information about a user.
|
|
27
|
+
To identify the account, either the account_id or the account_name must be provided.
|
|
28
|
+
"""
|
|
29
|
+
with db.conn(current_app) as conn, conn.cursor(row_factory=dict_row) as cursor:
|
|
30
|
+
|
|
31
|
+
account = get_account(cursor, account_id_or_name, create)
|
|
32
|
+
|
|
33
|
+
if set_role is not None:
|
|
34
|
+
update_role(cursor, account, set_role)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_account(cursor, account_id_or_name, create):
|
|
38
|
+
account_id = None
|
|
39
|
+
account_name = None
|
|
40
|
+
try:
|
|
41
|
+
account_id = UUID(account_id_or_name)
|
|
42
|
+
except ValueError:
|
|
43
|
+
account_name = account_id_or_name
|
|
44
|
+
|
|
45
|
+
if account_id is not None:
|
|
46
|
+
r = cursor.execute("SELECT id, name FROM accounts WHERE id = %s", [account_id]).fetchall()
|
|
47
|
+
elif account_name is not None:
|
|
48
|
+
r = cursor.execute("SELECT id, name FROM accounts WHERE name = %s", [account_name]).fetchall()
|
|
49
|
+
else:
|
|
50
|
+
raise click.ClickException("You must provide either an account_id or an account_name")
|
|
51
|
+
|
|
52
|
+
if create and not r:
|
|
53
|
+
if account_id is not None:
|
|
54
|
+
raise click.ClickException("You cannot create an account with an account_id, a name must be provided")
|
|
55
|
+
r = cursor.execute("INSERT INTO accounts (name) VALUES (%s) RETURNING id, name", [account_name]).fetchall()
|
|
56
|
+
|
|
57
|
+
if not r:
|
|
58
|
+
raise click.ClickException(f"Account {account_id_or_name} not found")
|
|
59
|
+
if len(r) > 1:
|
|
60
|
+
print(f"Several accounts found with name {account_id_or_name}")
|
|
61
|
+
for i in r:
|
|
62
|
+
print(f" * {i['id']}")
|
|
63
|
+
raise click.ClickException(f"Please provide an account_id instead")
|
|
64
|
+
|
|
65
|
+
return Account(id=r[0]["id"], name=r[0]["name"])
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def update_role(cursor, account, role):
|
|
69
|
+
try:
|
|
70
|
+
role = AccountRole(role)
|
|
71
|
+
except ValueError:
|
|
72
|
+
raise click.ClickException(f"Role {role} is not valid. Must be one of: admin or user")
|
|
73
|
+
|
|
74
|
+
print(f"Adding role {role.value} to account {account.name} ({account.id})")
|
|
75
|
+
cursor.execute("UPDATE accounts SET role = %s WHERE id = %s", [role.value, account.id])
|
geovisio/config_app.py
CHANGED
|
@@ -5,10 +5,15 @@ import datetime
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import Optional, Dict
|
|
7
7
|
import croniter
|
|
8
|
-
from pydantic import BaseModel
|
|
8
|
+
from pydantic import BaseModel, EmailStr
|
|
9
9
|
from pydantic.color import Color
|
|
10
10
|
from pydantic.networks import HttpUrl
|
|
11
11
|
import json
|
|
12
|
+
from flask import Flask, current_app
|
|
13
|
+
|
|
14
|
+
from geovisio.utils import website
|
|
15
|
+
from geovisio.utils.model_query import get_db_params_and_values
|
|
16
|
+
from geovisio.utils.website import Website
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
class ApiSummary(BaseModel):
|
|
@@ -16,6 +21,8 @@ class ApiSummary(BaseModel):
|
|
|
16
21
|
description: Dict[str, str] = {"en": "The open source photo mapping solution"}
|
|
17
22
|
logo: HttpUrl = "https://gitlab.com/panoramax/gitlab-profile/-/raw/main/images/logo.svg"
|
|
18
23
|
color: Color = "#bf360c"
|
|
24
|
+
email: EmailStr = "panoramax@panoramax.fr"
|
|
25
|
+
geo_coverage: Dict[str, str] = {"en": "Worldwide\nThe picture can be sent from anywhere in the world."}
|
|
19
26
|
|
|
20
27
|
|
|
21
28
|
class DefaultConfig:
|
|
@@ -40,6 +47,10 @@ class DefaultConfig:
|
|
|
40
47
|
DB_MAX_CNX = 10
|
|
41
48
|
DB_STATEMENT_TIMEOUT = 5 * 60 * 1000 # default statement timeout in ms (5mn)
|
|
42
49
|
API_ACCEPT_DUPLICATE = False
|
|
50
|
+
API_ENFORCE_TOS_ACCEPTANCE = False # if True, users won't be able to upload pictures without accepting the terms of service
|
|
51
|
+
API_WEBSITE_URL = (
|
|
52
|
+
website.WEBSITE_UNDER_SAME_HOST
|
|
53
|
+
) # by default we consider that there is a panoramax website on the same host as the API
|
|
43
54
|
|
|
44
55
|
|
|
45
56
|
def read_config(app, test_config):
|
|
@@ -78,6 +89,9 @@ def read_config(app, test_config):
|
|
|
78
89
|
"API_PICTURES_LICENSE_URL",
|
|
79
90
|
"API_ACCEPT_DUPLICATE",
|
|
80
91
|
"API_GIT_VERSION",
|
|
92
|
+
"API_DEFAULT_COLLABORATIVE_METADATA_EDITING",
|
|
93
|
+
"API_ENFORCE_TOS_ACCEPTANCE",
|
|
94
|
+
"API_WEBSITE_URL",
|
|
81
95
|
# Picture process
|
|
82
96
|
"PICTURE_PROCESS_DERIVATES_STRATEGY",
|
|
83
97
|
"PICTURE_PROCESS_THREADS_LIMIT",
|
|
@@ -111,7 +125,7 @@ def read_config(app, test_config):
|
|
|
111
125
|
"CLIENT_ID": "OAUTH_CLIENT_ID",
|
|
112
126
|
"CLIENT_SECRET": "OAUTH_CLIENT_SECRET",
|
|
113
127
|
"NB_PROXIES": "INFRA_NB_PROXIES",
|
|
114
|
-
"SECRET_KEY": "
|
|
128
|
+
"SECRET_KEY": "FLASK_SECRET_KEY",
|
|
115
129
|
"SESSION_COOKIE_DOMAIN": "FLASK_SESSION_COOKIE_DOMAIN",
|
|
116
130
|
}
|
|
117
131
|
for legacyKey, newKey in legacyVariables.items():
|
|
@@ -175,6 +189,8 @@ def read_config(app, test_config):
|
|
|
175
189
|
f"{pageParam} variable points to invalid template '{app.config[pageParam]}' (not found in '{templateFolder}' folder)"
|
|
176
190
|
)
|
|
177
191
|
|
|
192
|
+
app.config["API_WEBSITE_URL"] = Website(app.config.get("API_WEBSITE_URL"))
|
|
193
|
+
|
|
178
194
|
# The default is to use only one only 1 thread to process uploaded pictures
|
|
179
195
|
# if set to 0 no background worker is run, if set to -1 all cpus will be used
|
|
180
196
|
app.config["PICTURE_PROCESS_THREADS_LIMIT"] = _get_threads_limit(app.config["PICTURE_PROCESS_THREADS_LIMIT"])
|
|
@@ -205,6 +221,8 @@ def read_config(app, test_config):
|
|
|
205
221
|
raise Exception(f"PICTURE_PROCESS_REFRESH_CRON should be a valid cron syntax, got '{cron_val}'")
|
|
206
222
|
|
|
207
223
|
app.config["API_ACCEPT_DUPLICATE"] = _read_bool(app.config, "API_ACCEPT_DUPLICATE")
|
|
224
|
+
app.config["API_ENFORCE_TOS_ACCEPTANCE"] = _read_bool(app.config, "API_ENFORCE_TOS_ACCEPTANCE")
|
|
225
|
+
app.config["API_DEFAULT_COLLABORATIVE_METADATA_EDITING"] = _read_bool(app.config, "API_DEFAULT_COLLABORATIVE_METADATA_EDITING")
|
|
208
226
|
|
|
209
227
|
app.config["DB_STATEMENT_TIMEOUT"] = int(app.config["DB_STATEMENT_TIMEOUT"])
|
|
210
228
|
|
|
@@ -212,7 +230,21 @@ def read_config(app, test_config):
|
|
|
212
230
|
# Add generated config vars
|
|
213
231
|
#
|
|
214
232
|
app.url_map.strict_slashes = False
|
|
215
|
-
|
|
233
|
+
|
|
234
|
+
if app.config.get("API_COMPRESSION", True) is False:
|
|
235
|
+
# Note that this API_COMPRESSION variable is only used in tests
|
|
236
|
+
app.config["COMPRESS_MIMETYPES"] = []
|
|
237
|
+
else:
|
|
238
|
+
app.config["COMPRESS_MIMETYPES"] = [
|
|
239
|
+
"text/html",
|
|
240
|
+
"text/css",
|
|
241
|
+
"text/plain",
|
|
242
|
+
"text/xml",
|
|
243
|
+
"application/x-javascript",
|
|
244
|
+
"application/json",
|
|
245
|
+
"application/rss+xml",
|
|
246
|
+
"application/geo+json",
|
|
247
|
+
]
|
|
216
248
|
app.config["EXECUTOR_MAX_WORKERS"] = app.config["PICTURE_PROCESS_THREADS_LIMIT"]
|
|
217
249
|
app.config["EXECUTOR_PROPAGATE_EXCEPTIONS"] = True # propagate the excecutor's exceptions, to be able to trace them
|
|
218
250
|
|
|
@@ -248,7 +280,57 @@ def _get_threads_limit(param: str) -> int:
|
|
|
248
280
|
nb_cpu = os.cpu_count()
|
|
249
281
|
if p == -1:
|
|
250
282
|
if nb_cpu is None:
|
|
251
|
-
logging.
|
|
283
|
+
logging.warning("Number of cpu is unknown, using only 1 thread")
|
|
252
284
|
return 1
|
|
253
285
|
return nb_cpu
|
|
254
286
|
return min(p, os.cpu_count() or 1)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class DBConfiguration(BaseModel):
|
|
290
|
+
"""Configuration persisted in the database.
|
|
291
|
+
Not all configurations are meant to be persisted in the database"""
|
|
292
|
+
|
|
293
|
+
collaborative_metadata: Optional[bool] = None
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def persist_config(app: Flask):
|
|
297
|
+
"""
|
|
298
|
+
Persist the configuration in the database if needed.
|
|
299
|
+
|
|
300
|
+
Note that the configuration can only be initialized like this, if the configuration has been changed in the database, it will not be updated using environment variables.
|
|
301
|
+
"""
|
|
302
|
+
from geovisio.utils import db
|
|
303
|
+
from psycopg.rows import class_row
|
|
304
|
+
from psycopg.sql import SQL, Literal
|
|
305
|
+
from psycopg.errors import UndefinedTable
|
|
306
|
+
|
|
307
|
+
with db.conn(app) as conn, conn.transaction() as tr, conn.cursor(row_factory=class_row(DBConfiguration)) as cur:
|
|
308
|
+
try:
|
|
309
|
+
db_config = cur.execute("SELECT * FROM configurations LIMIT 1").fetchone()
|
|
310
|
+
except UndefinedTable:
|
|
311
|
+
logging.warning("Database schema has not been updated yet, configuration will not be persisted")
|
|
312
|
+
return
|
|
313
|
+
if not db_config:
|
|
314
|
+
raise Exception("Database has not been correctly initialized, there should always be a default")
|
|
315
|
+
config_to_persist = DBConfiguration()
|
|
316
|
+
|
|
317
|
+
# add the fields we want to persist here
|
|
318
|
+
collaborative_metadata = app.config["API_DEFAULT_COLLABORATIVE_METADATA_EDITING"]
|
|
319
|
+
if db_config.collaborative_metadata is None:
|
|
320
|
+
config_to_persist.collaborative_metadata = collaborative_metadata
|
|
321
|
+
elif db_config.collaborative_metadata != collaborative_metadata and collaborative_metadata is not None:
|
|
322
|
+
logging.warning(
|
|
323
|
+
"The environment variable `API_DEFAULT_COLLABORATIVE_METADATA_EDITING` has a different value than its value in the database, it will be ignored. Update the `collaborative_metadata` field in the database if you want to change it."
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
params_as_dict = get_db_params_and_values(config_to_persist)
|
|
327
|
+
fields = params_as_dict.fields_for_set()
|
|
328
|
+
if not params_as_dict.has_updates():
|
|
329
|
+
return
|
|
330
|
+
|
|
331
|
+
logging.info("Persisting configuration to the database from environement variables")
|
|
332
|
+
# Persist all set fields in the database
|
|
333
|
+
cur.execute(
|
|
334
|
+
SQL("UPDATE configurations SET {fields} RETURNING *").format(fields=fields),
|
|
335
|
+
params_as_dict.params_as_dict,
|
|
336
|
+
)
|
geovisio/templates/main.html
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
<script>
|
|
31
31
|
var baseUrl = window.location.href.replace(/\/$/, '');
|
|
32
|
-
var viewerUrl = "https://cdn.jsdelivr.net/npm/
|
|
32
|
+
var viewerUrl = "https://cdn.jsdelivr.net/npm/@panoramax/web-viewer@~3.2/build";
|
|
33
33
|
function encodeHTML(html) {
|
|
34
34
|
return html
|
|
35
35
|
.replace(/</g, "<")
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
+'<script>\n'
|
|
69
69
|
+'\t// All options available are listed here\n'
|
|
70
70
|
+'\t// https://gitlab.com/panoramax/clients/web-viewer/-/blob/develop/docs/02_Usage.md\n'
|
|
71
|
-
+'\tvar instance = new
|
|
71
|
+
+'\tvar instance = new Panoramax.default(\n'
|
|
72
72
|
+'\t\t"viewer",\n'
|
|
73
73
|
+'\t\t"'+baseUrl+'/api",\n'
|
|
74
74
|
+'\t\t{ map: true }\n'
|
geovisio/templates/viewer.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<link rel="shortcut icon" href="/favicon.ico" />
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="/static/img/favicon.svg" />
|
|
8
8
|
<title>GeoVisio</title>
|
|
9
|
-
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/
|
|
9
|
+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@panoramax/web-viewer@~3.2/build/index.css" />
|
|
10
10
|
<style>
|
|
11
11
|
#viewer {
|
|
12
12
|
position: absolute;
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
<noscript>{%trans%}You need to enable JavaScript to run this app.{%endtrans%}</noscript>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
-
<script src="https://cdn.jsdelivr.net/npm/
|
|
25
|
+
<script src="https://cdn.jsdelivr.net/npm/@panoramax/web-viewer@~3.2/build/index.js"></script>
|
|
26
26
|
<script>
|
|
27
|
-
var instance = new
|
|
27
|
+
var instance = new Panoramax.default(
|
|
28
28
|
"viewer",
|
|
29
29
|
"/api",
|
|
30
30
|
{ map: { startWide: true } }
|
|
Binary file
|