OpenGeodeWeb-Back 5.10.0rc22__py3-none-any.whl → 5.14.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.
- opengeodeweb_back/app.py +173 -0
- opengeodeweb_back/app_config.py +1 -10
- opengeodeweb_back/geode_functions.py +44 -283
- opengeodeweb_back/geode_objects/__init__.py +61 -0
- opengeodeweb_back/geode_objects/geode_brep.py +102 -0
- opengeodeweb_back/geode_objects/geode_cross_section.py +75 -0
- opengeodeweb_back/geode_objects/geode_edged_curve2d.py +107 -0
- opengeodeweb_back/geode_objects/geode_edged_curve3d.py +107 -0
- opengeodeweb_back/geode_objects/geode_graph.py +76 -0
- opengeodeweb_back/geode_objects/geode_grid2d.py +30 -0
- opengeodeweb_back/geode_objects/geode_grid3d.py +30 -0
- opengeodeweb_back/geode_objects/geode_hybrid_solid3d.py +71 -0
- opengeodeweb_back/geode_objects/geode_implicit_cross_section.py +81 -0
- opengeodeweb_back/geode_objects/geode_implicit_structural_model.py +85 -0
- opengeodeweb_back/geode_objects/geode_light_regular_grid2d.py +72 -0
- opengeodeweb_back/geode_objects/geode_light_regular_grid3d.py +72 -0
- opengeodeweb_back/geode_objects/geode_mesh.py +19 -0
- opengeodeweb_back/geode_objects/geode_model.py +22 -0
- opengeodeweb_back/geode_objects/geode_object.py +78 -0
- opengeodeweb_back/geode_objects/geode_point_set2d.py +105 -0
- opengeodeweb_back/geode_objects/geode_point_set3d.py +105 -0
- opengeodeweb_back/geode_objects/geode_polygonal_surface2d.py +73 -0
- opengeodeweb_back/geode_objects/geode_polygonal_surface3d.py +73 -0
- opengeodeweb_back/geode_objects/geode_polyhedral_solid3d.py +73 -0
- opengeodeweb_back/geode_objects/geode_raster_image2d.py +83 -0
- opengeodeweb_back/geode_objects/geode_raster_image3d.py +83 -0
- opengeodeweb_back/geode_objects/geode_regular_grid2d.py +78 -0
- opengeodeweb_back/geode_objects/geode_regular_grid3d.py +78 -0
- opengeodeweb_back/geode_objects/geode_section.py +106 -0
- opengeodeweb_back/geode_objects/geode_solid_mesh3d.py +61 -0
- opengeodeweb_back/geode_objects/geode_structural_model.py +78 -0
- opengeodeweb_back/geode_objects/geode_surface_mesh2d.py +66 -0
- opengeodeweb_back/geode_objects/geode_surface_mesh3d.py +66 -0
- opengeodeweb_back/geode_objects/geode_tetrahedral_solid3d.py +73 -0
- opengeodeweb_back/geode_objects/geode_triangulated_surface2d.py +77 -0
- opengeodeweb_back/geode_objects/geode_triangulated_surface3d.py +77 -0
- opengeodeweb_back/geode_objects/geode_vertex_set.py +81 -0
- opengeodeweb_back/geode_objects/types.py +75 -0
- opengeodeweb_back/routes/blueprint_routes.py +352 -231
- opengeodeweb_back/routes/create/blueprint_create.py +121 -0
- opengeodeweb_back/routes/create/schemas/__init__.py +3 -0
- opengeodeweb_back/routes/create/schemas/create_aoi.json +45 -0
- opengeodeweb_back/routes/create/schemas/create_aoi.py +25 -0
- opengeodeweb_back/routes/create/schemas/create_point.json +29 -0
- opengeodeweb_back/routes/create/schemas/create_point.py +13 -0
- opengeodeweb_back/routes/create/schemas/create_voi.json +36 -0
- opengeodeweb_back/routes/create/schemas/create_voi.py +24 -0
- opengeodeweb_back/routes/models/blueprint_models.py +27 -27
- opengeodeweb_back/routes/models/schemas/__init__.py +2 -0
- opengeodeweb_back/routes/models/schemas/mesh_components.py +10 -0
- opengeodeweb_back/routes/models/schemas/vtm_component_indices.py +10 -0
- opengeodeweb_back/routes/schemas/__init__.py +17 -0
- opengeodeweb_back/routes/schemas/allowed_files.json +6 -8
- opengeodeweb_back/routes/schemas/allowed_files.py +10 -0
- opengeodeweb_back/routes/schemas/allowed_objects.json +1 -8
- opengeodeweb_back/routes/schemas/allowed_objects.py +10 -0
- opengeodeweb_back/routes/schemas/cell_attribute_names.json +13 -0
- opengeodeweb_back/routes/schemas/cell_attribute_names.py +10 -0
- opengeodeweb_back/routes/schemas/export_project.json +21 -0
- opengeodeweb_back/routes/schemas/export_project.py +12 -0
- opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.json +2 -2
- opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.py +11 -0
- opengeodeweb_back/routes/schemas/geographic_coordinate_systems.json +2 -2
- opengeodeweb_back/routes/schemas/geographic_coordinate_systems.py +10 -0
- opengeodeweb_back/routes/schemas/import_project.json +10 -0
- opengeodeweb_back/routes/schemas/import_project.py +10 -0
- opengeodeweb_back/routes/schemas/inspect_file.json +2 -2
- opengeodeweb_back/routes/schemas/inspect_file.py +11 -0
- opengeodeweb_back/routes/schemas/kill.json +10 -0
- opengeodeweb_back/routes/schemas/kill.py +10 -0
- opengeodeweb_back/routes/schemas/missing_files.json +2 -2
- opengeodeweb_back/routes/schemas/missing_files.py +11 -0
- opengeodeweb_back/routes/schemas/ping.py +10 -0
- opengeodeweb_back/routes/schemas/polygon_attribute_names.py +10 -0
- opengeodeweb_back/routes/schemas/polyhedron_attribute_names.py +10 -0
- opengeodeweb_back/routes/schemas/save_viewable_file.json +2 -2
- opengeodeweb_back/routes/schemas/save_viewable_file.py +11 -0
- opengeodeweb_back/routes/schemas/texture_coordinates.py +10 -0
- opengeodeweb_back/routes/schemas/upload_file.py +11 -0
- opengeodeweb_back/routes/schemas/vertex_attribute_names.py +10 -0
- opengeodeweb_back/test_utils.py +9 -3
- opengeodeweb_back/utils_functions.py +93 -88
- {opengeodeweb_back-5.10.0rc22.dist-info → opengeodeweb_back-5.14.1.dist-info}/METADATA +17 -22
- opengeodeweb_back-5.14.1.dist-info/RECORD +98 -0
- opengeodeweb_back-5.14.1.dist-info/entry_points.txt +2 -0
- opengeodeweb_back/geode_objects.py +0 -570
- opengeodeweb_back/routes/schemas/create_point.json +0 -29
- opengeodeweb_back-5.10.0rc22.dist-info/RECORD +0 -30
- {opengeodeweb_back-5.10.0rc22.dist-info → opengeodeweb_back-5.14.1.dist-info}/WHEEL +0 -0
- {opengeodeweb_back-5.10.0rc22.dist-info → opengeodeweb_back-5.14.1.dist-info}/licenses/LICENSE +0 -0
- {opengeodeweb_back-5.10.0rc22.dist-info → opengeodeweb_back-5.14.1.dist-info}/top_level.txt +0 -0
|
@@ -1,143 +1,122 @@
|
|
|
1
1
|
# Standard library imports
|
|
2
|
-
import json
|
|
3
2
|
import os
|
|
4
3
|
import time
|
|
4
|
+
import shutil
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
# Third party imports
|
|
7
8
|
import flask
|
|
8
|
-
import opengeode
|
|
9
9
|
import werkzeug
|
|
10
|
+
import zipfile
|
|
11
|
+
import opengeode_geosciences as og_geosciences
|
|
12
|
+
from opengeodeweb_microservice.schemas import get_schemas_dict
|
|
13
|
+
from opengeodeweb_microservice.database.data import Data
|
|
14
|
+
from opengeodeweb_microservice.database.connection import get_session
|
|
15
|
+
from opengeodeweb_microservice.database import connection
|
|
10
16
|
|
|
11
17
|
# Local application imports
|
|
12
|
-
from .. import geode_functions, utils_functions
|
|
13
|
-
|
|
14
18
|
from .models import blueprint_models
|
|
19
|
+
from . import schemas
|
|
20
|
+
from opengeodeweb_back import geode_functions, utils_functions
|
|
21
|
+
from opengeodeweb_back.geode_objects import geode_objects
|
|
22
|
+
from opengeodeweb_back.geode_objects.types import geode_object_type
|
|
23
|
+
from opengeodeweb_back.geode_objects.geode_mesh import GeodeMesh
|
|
24
|
+
from opengeodeweb_back.geode_objects.geode_grid2d import GeodeGrid2D
|
|
25
|
+
from opengeodeweb_back.geode_objects.geode_grid3d import GeodeGrid3D
|
|
26
|
+
from opengeodeweb_back.geode_objects.geode_surface_mesh2d import GeodeSurfaceMesh2D
|
|
27
|
+
from opengeodeweb_back.geode_objects.geode_surface_mesh3d import GeodeSurfaceMesh3D
|
|
28
|
+
from opengeodeweb_back.geode_objects.geode_solid_mesh3d import GeodeSolidMesh3D
|
|
15
29
|
|
|
16
30
|
routes = flask.Blueprint("routes", __name__, url_prefix="/opengeodeweb_back")
|
|
17
31
|
|
|
18
32
|
|
|
19
|
-
@routes.before_request
|
|
20
|
-
def before_request():
|
|
21
|
-
if "ping" not in flask.request.path:
|
|
22
|
-
utils_functions.increment_request_counter(flask.current_app)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@routes.teardown_request
|
|
26
|
-
def teardown_request(exception):
|
|
27
|
-
|
|
28
|
-
if "ping" not in flask.request.path:
|
|
29
|
-
utils_functions.decrement_request_counter(flask.current_app)
|
|
30
|
-
utils_functions.update_last_request_time(flask.current_app)
|
|
31
|
-
|
|
32
|
-
|
|
33
33
|
routes.register_blueprint(
|
|
34
34
|
blueprint_models.routes,
|
|
35
35
|
url_prefix=blueprint_models.routes.url_prefix,
|
|
36
36
|
name=blueprint_models.routes.name,
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
schemas = os.path.join(os.path.dirname(__file__), "schemas")
|
|
41
|
-
|
|
42
|
-
with open(
|
|
43
|
-
os.path.join(schemas, "allowed_files.json"),
|
|
44
|
-
"r",
|
|
45
|
-
) as file:
|
|
46
|
-
allowed_files_json = json.load(file)
|
|
39
|
+
schemas_dict = get_schemas_dict(os.path.join(os.path.dirname(__file__), "schemas"))
|
|
47
40
|
|
|
48
41
|
|
|
49
42
|
@routes.route(
|
|
50
|
-
|
|
51
|
-
methods=
|
|
43
|
+
schemas_dict["allowed_files"]["route"],
|
|
44
|
+
methods=schemas_dict["allowed_files"]["methods"],
|
|
52
45
|
)
|
|
53
|
-
def allowed_files():
|
|
54
|
-
utils_functions.validate_request(flask.request,
|
|
55
|
-
extensions =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
with open(
|
|
62
|
-
os.path.join(schemas, "upload_file.json"),
|
|
63
|
-
"r",
|
|
64
|
-
) as file:
|
|
65
|
-
upload_file_json = json.load(file)
|
|
46
|
+
def allowed_files() -> flask.Response:
|
|
47
|
+
utils_functions.validate_request(flask.request, schemas_dict["allowed_files"])
|
|
48
|
+
extensions: set[str] = set()
|
|
49
|
+
for geode_object in geode_objects.values():
|
|
50
|
+
for extension in geode_object.input_extensions():
|
|
51
|
+
extensions.add(extension)
|
|
52
|
+
return flask.make_response({"extensions": list(extensions)}, 200)
|
|
66
53
|
|
|
67
54
|
|
|
68
55
|
@routes.route(
|
|
69
|
-
|
|
70
|
-
methods=
|
|
56
|
+
schemas_dict["upload_file"]["route"],
|
|
57
|
+
methods=schemas_dict["upload_file"]["methods"],
|
|
71
58
|
)
|
|
72
|
-
def upload_file():
|
|
73
|
-
if flask.request.method == "OPTIONS":
|
|
74
|
-
return flask.make_response({}, 200)
|
|
75
|
-
|
|
59
|
+
def upload_file() -> flask.Response:
|
|
76
60
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
|
77
61
|
if not os.path.exists(UPLOAD_FOLDER):
|
|
78
|
-
os.
|
|
62
|
+
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
|
63
|
+
|
|
79
64
|
file = flask.request.files["file"]
|
|
80
65
|
filename = werkzeug.utils.secure_filename(os.path.basename(file.filename))
|
|
81
66
|
file.save(os.path.join(UPLOAD_FOLDER, filename))
|
|
82
67
|
return flask.make_response({"message": "File uploaded"}, 201)
|
|
83
68
|
|
|
84
69
|
|
|
85
|
-
with open(
|
|
86
|
-
os.path.join(schemas, "allowed_objects.json"),
|
|
87
|
-
"r",
|
|
88
|
-
) as file:
|
|
89
|
-
allowed_objects_json = json.load(file)
|
|
90
|
-
|
|
91
|
-
|
|
92
70
|
@routes.route(
|
|
93
|
-
|
|
94
|
-
methods=
|
|
71
|
+
schemas_dict["allowed_objects"]["route"],
|
|
72
|
+
methods=schemas_dict["allowed_objects"]["methods"],
|
|
95
73
|
)
|
|
96
|
-
def allowed_objects():
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
utils_functions.validate_request(flask.request, allowed_objects_json)
|
|
101
|
-
file_absolute_path = geode_functions.upload_file_path(
|
|
102
|
-
flask.request.get_json()["filename"]
|
|
74
|
+
def allowed_objects() -> flask.Response:
|
|
75
|
+
json_data = utils_functions.validate_request(
|
|
76
|
+
flask.request, schemas_dict["allowed_objects"]
|
|
103
77
|
)
|
|
104
|
-
|
|
105
|
-
|
|
78
|
+
params = schemas.AllowedObjects.from_dict(json_data)
|
|
79
|
+
file_absolute_path = geode_functions.upload_file_path(params.filename)
|
|
80
|
+
file_extension = utils_functions.extension_from_filename(
|
|
81
|
+
os.path.basename(file_absolute_path)
|
|
106
82
|
)
|
|
83
|
+
allowed_objects = {}
|
|
84
|
+
for geode_object_type, geode_object in geode_objects.items():
|
|
85
|
+
if file_extension not in geode_object.input_extensions():
|
|
86
|
+
continue
|
|
87
|
+
loadability_score = geode_object.is_loadable(file_absolute_path)
|
|
88
|
+
priority_score = geode_object.object_priority(file_absolute_path)
|
|
89
|
+
allowed_objects[geode_object_type] = {
|
|
90
|
+
"is_loadable": loadability_score.value(),
|
|
91
|
+
"object_priority": priority_score,
|
|
92
|
+
}
|
|
107
93
|
return flask.make_response({"allowed_objects": allowed_objects}, 200)
|
|
108
94
|
|
|
109
95
|
|
|
110
|
-
with open(
|
|
111
|
-
os.path.join(schemas, "missing_files.json"),
|
|
112
|
-
"r",
|
|
113
|
-
) as file:
|
|
114
|
-
missing_files_json = json.load(file)
|
|
115
|
-
|
|
116
|
-
|
|
117
96
|
@routes.route(
|
|
118
|
-
|
|
119
|
-
methods=
|
|
97
|
+
schemas_dict["missing_files"]["route"],
|
|
98
|
+
methods=schemas_dict["missing_files"]["methods"],
|
|
120
99
|
)
|
|
121
|
-
def missing_files():
|
|
122
|
-
utils_functions.validate_request(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
100
|
+
def missing_files() -> flask.Response:
|
|
101
|
+
json_data = utils_functions.validate_request(
|
|
102
|
+
flask.request, schemas_dict["missing_files"]
|
|
103
|
+
)
|
|
104
|
+
params = schemas.MissingFiles.from_dict(json_data)
|
|
105
|
+
file_path = geode_functions.upload_file_path(params.filename)
|
|
106
|
+
geode_object = geode_functions.geode_object_from_string(params.geode_object_type)
|
|
107
|
+
additional_files = geode_object.additional_files(
|
|
127
108
|
file_path,
|
|
128
109
|
)
|
|
129
|
-
|
|
130
110
|
has_missing_files = any(
|
|
131
111
|
file.is_missing
|
|
132
112
|
for file in additional_files.mandatory_files + additional_files.optional_files
|
|
133
113
|
)
|
|
134
|
-
|
|
135
114
|
mandatory_files = [
|
|
136
115
|
os.path.basename(file.filename)
|
|
137
116
|
for file in additional_files.mandatory_files
|
|
138
117
|
if file.is_missing
|
|
139
118
|
]
|
|
140
|
-
|
|
119
|
+
additional_files_array = [
|
|
141
120
|
os.path.basename(file.filename)
|
|
142
121
|
for file in additional_files.optional_files
|
|
143
122
|
if file.is_missing
|
|
@@ -147,27 +126,26 @@ def missing_files():
|
|
|
147
126
|
{
|
|
148
127
|
"has_missing_files": has_missing_files,
|
|
149
128
|
"mandatory_files": mandatory_files,
|
|
150
|
-
"additional_files":
|
|
129
|
+
"additional_files": additional_files_array,
|
|
151
130
|
},
|
|
152
131
|
200,
|
|
153
132
|
)
|
|
154
133
|
|
|
155
134
|
|
|
156
|
-
with open(
|
|
157
|
-
os.path.join(schemas, "geographic_coordinate_systems.json"),
|
|
158
|
-
"r",
|
|
159
|
-
) as file:
|
|
160
|
-
geographic_coordinate_systems_json = json.load(file)
|
|
161
|
-
|
|
162
|
-
|
|
163
135
|
@routes.route(
|
|
164
|
-
|
|
165
|
-
methods=
|
|
136
|
+
schemas_dict["geographic_coordinate_systems"]["route"],
|
|
137
|
+
methods=schemas_dict["geographic_coordinate_systems"]["methods"],
|
|
166
138
|
)
|
|
167
|
-
def crs_converter_geographic_coordinate_systems():
|
|
168
|
-
utils_functions.validate_request(
|
|
169
|
-
|
|
170
|
-
|
|
139
|
+
def crs_converter_geographic_coordinate_systems() -> flask.Response:
|
|
140
|
+
json_data = utils_functions.validate_request(
|
|
141
|
+
flask.request, schemas_dict["geographic_coordinate_systems"]
|
|
142
|
+
)
|
|
143
|
+
params = schemas.GeographicCoordinateSystems.from_dict(json_data)
|
|
144
|
+
geode_object = geode_functions.geode_object_from_string(params.geode_object_type)
|
|
145
|
+
infos = (
|
|
146
|
+
og_geosciences.GeographicCoordinateSystem3D.geographic_coordinate_systems()
|
|
147
|
+
if geode_object.is_3D()
|
|
148
|
+
else og_geosciences.GeographicCoordinateSystem2D.geographic_coordinate_systems()
|
|
171
149
|
)
|
|
172
150
|
crs_list = []
|
|
173
151
|
for info in infos:
|
|
@@ -176,59 +154,70 @@ def crs_converter_geographic_coordinate_systems():
|
|
|
176
154
|
crs["code"] = info.code
|
|
177
155
|
crs["authority"] = info.authority
|
|
178
156
|
crs_list.append(crs)
|
|
179
|
-
|
|
180
157
|
return flask.make_response({"crs_list": crs_list}, 200)
|
|
181
158
|
|
|
182
159
|
|
|
183
|
-
with open(
|
|
184
|
-
os.path.join(schemas, "inspect_file.json"),
|
|
185
|
-
"r",
|
|
186
|
-
) as file:
|
|
187
|
-
inspect_file_json = json.load(file)
|
|
188
|
-
|
|
189
|
-
|
|
190
160
|
@routes.route(
|
|
191
|
-
|
|
192
|
-
methods=
|
|
161
|
+
schemas_dict["inspect_file"]["route"],
|
|
162
|
+
methods=schemas_dict["inspect_file"]["methods"],
|
|
193
163
|
)
|
|
194
|
-
def inspect_file():
|
|
195
|
-
utils_functions.validate_request(
|
|
196
|
-
|
|
197
|
-
file_path = geode_functions.upload_file_path(flask.request.get_json()["filename"])
|
|
198
|
-
data = geode_functions.load(
|
|
199
|
-
flask.request.get_json()["input_geode_object"], file_path
|
|
200
|
-
)
|
|
201
|
-
class_inspector = geode_functions.inspect(
|
|
202
|
-
flask.request.get_json()["input_geode_object"], data
|
|
164
|
+
def inspect_file() -> flask.Response:
|
|
165
|
+
json_data = utils_functions.validate_request(
|
|
166
|
+
flask.request, schemas_dict["inspect_file"]
|
|
203
167
|
)
|
|
204
|
-
|
|
168
|
+
params = schemas.InspectFile.from_dict(json_data)
|
|
169
|
+
file_path = geode_functions.upload_file_path(params.filename)
|
|
170
|
+
geode_object = geode_functions.geode_object_from_string(
|
|
171
|
+
params.geode_object_type
|
|
172
|
+
).load(file_path)
|
|
173
|
+
inspection_data = geode_object.inspect()
|
|
174
|
+
inspection_result = extract_inspector_result(inspection_data)
|
|
205
175
|
return flask.make_response({"inspection_result": inspection_result}, 200)
|
|
206
176
|
|
|
207
177
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
178
|
+
def extract_inspector_result(inspection_data: Any) -> object:
|
|
179
|
+
new_object = {}
|
|
180
|
+
|
|
181
|
+
if hasattr(inspection_data, "inspection_type"):
|
|
182
|
+
new_object["title"] = inspection_data.inspection_type()
|
|
183
|
+
new_object["nb_issues"] = 0
|
|
184
|
+
new_object["children"] = []
|
|
185
|
+
for child in dir(inspection_data):
|
|
186
|
+
if child.startswith("__") or child in [
|
|
187
|
+
"inspection_type",
|
|
188
|
+
"string",
|
|
189
|
+
]:
|
|
190
|
+
continue
|
|
191
|
+
child_instance = getattr(inspection_data, child)
|
|
192
|
+
child_object = extract_inspector_result(child_instance)
|
|
193
|
+
new_object["children"].append(child_object)
|
|
194
|
+
if hasattr(child_object, "nb_issues"):
|
|
195
|
+
new_object["nb_issues"] += child_object.nb_issues()
|
|
196
|
+
else:
|
|
197
|
+
new_object["title"] = inspection_data.description()
|
|
198
|
+
nb_issues = inspection_data.nb_issues()
|
|
199
|
+
new_object["nb_issues"] = nb_issues
|
|
200
|
+
if nb_issues > 0:
|
|
201
|
+
issues = inspection_data.string().split("\n")
|
|
202
|
+
new_object["issues"] = issues
|
|
203
|
+
return new_object
|
|
213
204
|
|
|
214
205
|
|
|
215
206
|
@routes.route(
|
|
216
|
-
|
|
217
|
-
methods=
|
|
207
|
+
schemas_dict["geode_objects_and_output_extensions"]["route"],
|
|
208
|
+
methods=schemas_dict["geode_objects_and_output_extensions"]["methods"],
|
|
218
209
|
)
|
|
219
|
-
def geode_objects_and_output_extensions():
|
|
220
|
-
utils_functions.validate_request(
|
|
221
|
-
flask.request,
|
|
222
|
-
)
|
|
223
|
-
file_path = geode_functions.upload_file_path(flask.request.get_json()["filename"])
|
|
224
|
-
data = geode_functions.load(
|
|
225
|
-
flask.request.get_json()["input_geode_object"],
|
|
226
|
-
file_path,
|
|
210
|
+
def geode_objects_and_output_extensions() -> flask.Response:
|
|
211
|
+
json_data = utils_functions.validate_request(
|
|
212
|
+
flask.request, schemas_dict["geode_objects_and_output_extensions"]
|
|
227
213
|
)
|
|
214
|
+
params = schemas.GeodeObjectsAndOutputExtensions.from_dict(json_data)
|
|
215
|
+
file_path = geode_functions.upload_file_path(params.filename)
|
|
216
|
+
geode_object = geode_functions.geode_object_from_string(
|
|
217
|
+
params.geode_object_type
|
|
218
|
+
).load(file_path)
|
|
228
219
|
geode_objects_and_output_extensions = (
|
|
229
|
-
geode_functions.
|
|
230
|
-
flask.request.get_json()["input_geode_object"], data
|
|
231
|
-
)
|
|
220
|
+
geode_functions.geode_object_output_extensions(geode_object)
|
|
232
221
|
)
|
|
233
222
|
return flask.make_response(
|
|
234
223
|
{"geode_objects_and_output_extensions": geode_objects_and_output_extensions},
|
|
@@ -236,82 +225,53 @@ def geode_objects_and_output_extensions():
|
|
|
236
225
|
)
|
|
237
226
|
|
|
238
227
|
|
|
239
|
-
with open(
|
|
240
|
-
os.path.join(schemas, "save_viewable_file.json"),
|
|
241
|
-
"r",
|
|
242
|
-
) as file:
|
|
243
|
-
save_viewable_file_json = json.load(file)
|
|
244
|
-
|
|
245
|
-
|
|
246
228
|
@routes.route(
|
|
247
|
-
|
|
248
|
-
methods=
|
|
229
|
+
schemas_dict["save_viewable_file"]["route"],
|
|
230
|
+
methods=schemas_dict["save_viewable_file"]["methods"],
|
|
249
231
|
)
|
|
250
|
-
def save_viewable_file():
|
|
251
|
-
utils_functions.validate_request(
|
|
252
|
-
|
|
253
|
-
utils_functions.generate_native_viewable_and_light_viewable_from_file(
|
|
254
|
-
geode_object=flask.request.get_json()["input_geode_object"],
|
|
255
|
-
input_filename=flask.request.get_json()["filename"],
|
|
256
|
-
),
|
|
257
|
-
200,
|
|
232
|
+
def save_viewable_file() -> flask.Response:
|
|
233
|
+
json_data = utils_functions.validate_request(
|
|
234
|
+
flask.request, schemas_dict["save_viewable_file"]
|
|
258
235
|
)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
with open(os.path.join(schemas, "create_point.json"), "r") as file:
|
|
262
|
-
create_point_json = json.load(file)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
@routes.route(create_point_json["route"], methods=create_point_json["methods"])
|
|
266
|
-
def create_point():
|
|
267
|
-
utils_functions.validate_request(flask.request, create_point_json)
|
|
268
|
-
title = flask.request.get_json()["title"]
|
|
269
|
-
x = flask.request.get_json()["x"]
|
|
270
|
-
y = flask.request.get_json()["y"]
|
|
271
|
-
z = flask.request.get_json()["z"]
|
|
272
|
-
class_ = geode_functions.geode_object_class("PointSet3D")
|
|
273
|
-
PointSet3D = class_.create()
|
|
274
|
-
builder = geode_functions.create_builder("PointSet3D", PointSet3D)
|
|
275
|
-
builder.create_point(opengeode.Point3D([x, y, z]))
|
|
276
|
-
builder.set_name(title)
|
|
236
|
+
params = schemas.SaveViewableFile.from_dict(json_data)
|
|
277
237
|
return flask.make_response(
|
|
278
|
-
utils_functions.
|
|
279
|
-
|
|
238
|
+
utils_functions.generate_native_viewable_and_light_viewable_from_file(
|
|
239
|
+
geode_object_type=geode_object_type(params.geode_object_type),
|
|
240
|
+
input_file=params.filename,
|
|
280
241
|
),
|
|
281
242
|
200,
|
|
282
243
|
)
|
|
283
244
|
|
|
284
245
|
|
|
285
|
-
with open(os.path.join(schemas, "texture_coordinates.json"), "r") as file:
|
|
286
|
-
texture_coordinates_json = json.load(file)
|
|
287
|
-
|
|
288
|
-
|
|
289
246
|
@routes.route(
|
|
290
|
-
|
|
291
|
-
methods=
|
|
247
|
+
schemas_dict["texture_coordinates"]["route"],
|
|
248
|
+
methods=schemas_dict["texture_coordinates"]["methods"],
|
|
292
249
|
)
|
|
293
|
-
def texture_coordinates():
|
|
294
|
-
utils_functions.validate_request(
|
|
295
|
-
|
|
296
|
-
|
|
250
|
+
def texture_coordinates() -> flask.Response:
|
|
251
|
+
json_data = utils_functions.validate_request(
|
|
252
|
+
flask.request, schemas_dict["texture_coordinates"]
|
|
253
|
+
)
|
|
254
|
+
params = schemas.TextureCoordinates.from_dict(json_data)
|
|
255
|
+
geode_object = geode_functions.load_geode_object(params.id)
|
|
256
|
+
if not isinstance(geode_object, GeodeSurfaceMesh2D | GeodeSurfaceMesh3D):
|
|
257
|
+
flask.abort(400, f"{params.id} is not a GeodeSurfaceMesh")
|
|
258
|
+
texture_coordinates = geode_object.texture_manager().texture_names()
|
|
297
259
|
return flask.make_response({"texture_coordinates": texture_coordinates}, 200)
|
|
298
260
|
|
|
299
261
|
|
|
300
|
-
with open(
|
|
301
|
-
os.path.join(schemas, "vertex_attribute_names.json"),
|
|
302
|
-
"r",
|
|
303
|
-
) as file:
|
|
304
|
-
vertex_attribute_names_json = json.load(file)
|
|
305
|
-
|
|
306
|
-
|
|
307
262
|
@routes.route(
|
|
308
|
-
|
|
309
|
-
methods=
|
|
263
|
+
schemas_dict["vertex_attribute_names"]["route"],
|
|
264
|
+
methods=schemas_dict["vertex_attribute_names"]["methods"],
|
|
310
265
|
)
|
|
311
|
-
def vertex_attribute_names():
|
|
312
|
-
utils_functions.validate_request(
|
|
313
|
-
|
|
314
|
-
|
|
266
|
+
def vertex_attribute_names() -> flask.Response:
|
|
267
|
+
json_data = utils_functions.validate_request(
|
|
268
|
+
flask.request, schemas_dict["vertex_attribute_names"]
|
|
269
|
+
)
|
|
270
|
+
params = schemas.VertexAttributeNames.from_dict(json_data)
|
|
271
|
+
geode_object = geode_functions.load_geode_object(params.id)
|
|
272
|
+
if not isinstance(geode_object, GeodeMesh):
|
|
273
|
+
flask.abort(400, f"{params.id} is not a GeodeMesh")
|
|
274
|
+
vertex_attribute_names = geode_object.vertex_attribute_manager().attribute_names()
|
|
315
275
|
return flask.make_response(
|
|
316
276
|
{
|
|
317
277
|
"vertex_attribute_names": vertex_attribute_names,
|
|
@@ -320,21 +280,40 @@ def vertex_attribute_names():
|
|
|
320
280
|
)
|
|
321
281
|
|
|
322
282
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
"
|
|
326
|
-
)
|
|
327
|
-
|
|
283
|
+
@routes.route(
|
|
284
|
+
schemas_dict["cell_attribute_names"]["route"],
|
|
285
|
+
methods=schemas_dict["cell_attribute_names"]["methods"],
|
|
286
|
+
)
|
|
287
|
+
def cell_attribute_names() -> flask.Response:
|
|
288
|
+
json_data = utils_functions.validate_request(
|
|
289
|
+
flask.request, schemas_dict["cell_attribute_names"]
|
|
290
|
+
)
|
|
291
|
+
params = schemas.PolygonAttributeNames.from_dict(json_data)
|
|
292
|
+
geode_object = geode_functions.load_geode_object(params.id)
|
|
293
|
+
if not isinstance(geode_object, GeodeGrid2D | GeodeGrid3D):
|
|
294
|
+
flask.abort(400, f"{params.id} is not a GeodeGrid")
|
|
295
|
+
cell_attribute_names = geode_object.cell_attribute_manager().attribute_names()
|
|
296
|
+
return flask.make_response(
|
|
297
|
+
{
|
|
298
|
+
"cell_attribute_names": cell_attribute_names,
|
|
299
|
+
},
|
|
300
|
+
200,
|
|
301
|
+
)
|
|
328
302
|
|
|
329
303
|
|
|
330
304
|
@routes.route(
|
|
331
|
-
|
|
332
|
-
methods=
|
|
305
|
+
schemas_dict["polygon_attribute_names"]["route"],
|
|
306
|
+
methods=schemas_dict["polygon_attribute_names"]["methods"],
|
|
333
307
|
)
|
|
334
|
-
def polygon_attribute_names():
|
|
335
|
-
utils_functions.validate_request(
|
|
336
|
-
|
|
337
|
-
|
|
308
|
+
def polygon_attribute_names() -> flask.Response:
|
|
309
|
+
json_data = utils_functions.validate_request(
|
|
310
|
+
flask.request, schemas_dict["polygon_attribute_names"]
|
|
311
|
+
)
|
|
312
|
+
params = schemas.PolygonAttributeNames.from_dict(json_data)
|
|
313
|
+
geode_object = geode_functions.load_geode_object(params.id)
|
|
314
|
+
if not isinstance(geode_object, GeodeSurfaceMesh2D | GeodeSurfaceMesh3D):
|
|
315
|
+
flask.abort(400, f"{params.id} is not a GeodeSurfaceMesh")
|
|
316
|
+
polygon_attribute_names = geode_object.polygon_attribute_manager().attribute_names()
|
|
338
317
|
return flask.make_response(
|
|
339
318
|
{
|
|
340
319
|
"polygon_attribute_names": polygon_attribute_names,
|
|
@@ -343,21 +322,21 @@ def polygon_attribute_names():
|
|
|
343
322
|
)
|
|
344
323
|
|
|
345
324
|
|
|
346
|
-
with open(
|
|
347
|
-
os.path.join(schemas, "polyhedron_attribute_names.json"),
|
|
348
|
-
"r",
|
|
349
|
-
) as file:
|
|
350
|
-
polyhedron_attribute_names_json = json.load(file)
|
|
351
|
-
|
|
352
|
-
|
|
353
325
|
@routes.route(
|
|
354
|
-
|
|
355
|
-
methods=
|
|
326
|
+
schemas_dict["polyhedron_attribute_names"]["route"],
|
|
327
|
+
methods=schemas_dict["polyhedron_attribute_names"]["methods"],
|
|
356
328
|
)
|
|
357
|
-
def polyhedron_attribute_names():
|
|
358
|
-
utils_functions.validate_request(
|
|
359
|
-
|
|
360
|
-
|
|
329
|
+
def polyhedron_attribute_names() -> flask.Response:
|
|
330
|
+
json_data = utils_functions.validate_request(
|
|
331
|
+
flask.request, schemas_dict["polyhedron_attribute_names"]
|
|
332
|
+
)
|
|
333
|
+
params = schemas.PolyhedronAttributeNames.from_dict(json_data)
|
|
334
|
+
geode_object = geode_functions.load_geode_object(params.id)
|
|
335
|
+
if not isinstance(geode_object, GeodeSolidMesh3D):
|
|
336
|
+
flask.abort(400, f"{params.id} is not a GeodeSolidMesh")
|
|
337
|
+
polyhedron_attribute_names = (
|
|
338
|
+
geode_object.polyhedron_attribute_manager().attribute_names()
|
|
339
|
+
)
|
|
361
340
|
return flask.make_response(
|
|
362
341
|
{
|
|
363
342
|
"polyhedron_attribute_names": polyhedron_attribute_names,
|
|
@@ -366,18 +345,160 @@ def polyhedron_attribute_names():
|
|
|
366
345
|
)
|
|
367
346
|
|
|
368
347
|
|
|
369
|
-
with open(
|
|
370
|
-
os.path.join(schemas, "ping.json"),
|
|
371
|
-
"r",
|
|
372
|
-
) as file:
|
|
373
|
-
ping_json = json.load(file)
|
|
374
|
-
|
|
375
|
-
|
|
376
348
|
@routes.route(
|
|
377
|
-
|
|
378
|
-
methods=
|
|
349
|
+
schemas_dict["ping"]["route"],
|
|
350
|
+
methods=schemas_dict["ping"]["methods"],
|
|
379
351
|
)
|
|
380
|
-
def ping():
|
|
381
|
-
utils_functions.validate_request(flask.request,
|
|
352
|
+
def ping() -> flask.Response:
|
|
353
|
+
utils_functions.validate_request(flask.request, schemas_dict["ping"])
|
|
382
354
|
flask.current_app.config.update(LAST_PING_TIME=time.time())
|
|
383
355
|
return flask.make_response({"message": "Flask server is running"}, 200)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@routes.route(schemas_dict["kill"]["route"], methods=schemas_dict["kill"]["methods"])
|
|
359
|
+
def kill() -> flask.Response:
|
|
360
|
+
print("Manual server kill, shutting down...", flush=True)
|
|
361
|
+
os._exit(0)
|
|
362
|
+
return flask.make_response({"message": "Flask server is dead"}, 200)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@routes.route(
|
|
366
|
+
schemas_dict["export_project"]["route"],
|
|
367
|
+
methods=schemas_dict["export_project"]["methods"],
|
|
368
|
+
)
|
|
369
|
+
def export_project() -> flask.Response:
|
|
370
|
+
json_data = utils_functions.validate_request(
|
|
371
|
+
flask.request, schemas_dict["export_project"]
|
|
372
|
+
)
|
|
373
|
+
params = schemas.ExportProject.from_dict(json_data)
|
|
374
|
+
|
|
375
|
+
project_folder: str = flask.current_app.config["DATA_FOLDER_PATH"]
|
|
376
|
+
os.makedirs(project_folder, exist_ok=True)
|
|
377
|
+
|
|
378
|
+
filename: str = werkzeug.utils.secure_filename(os.path.basename(params.filename))
|
|
379
|
+
if not filename.lower().endswith(".vease"):
|
|
380
|
+
flask.abort(400, "Requested filename must end with .vease")
|
|
381
|
+
export_vease_path = os.path.join(project_folder, filename)
|
|
382
|
+
|
|
383
|
+
with get_session() as session:
|
|
384
|
+
rows = session.query(Data.id, Data.input_file, Data.additional_files).all()
|
|
385
|
+
|
|
386
|
+
with zipfile.ZipFile(
|
|
387
|
+
export_vease_path, "w", compression=zipfile.ZIP_DEFLATED
|
|
388
|
+
) as zip_file:
|
|
389
|
+
database_root_path = os.path.join(project_folder, "project.db")
|
|
390
|
+
if os.path.isfile(database_root_path):
|
|
391
|
+
zip_file.write(database_root_path, "project.db")
|
|
392
|
+
|
|
393
|
+
for data_id, input_file, additional_files in rows:
|
|
394
|
+
base_dir = os.path.join(project_folder, data_id)
|
|
395
|
+
|
|
396
|
+
input_path = os.path.join(base_dir, str(input_file))
|
|
397
|
+
if os.path.isfile(input_path):
|
|
398
|
+
zip_file.write(input_path, os.path.join(data_id, str(input_file)))
|
|
399
|
+
|
|
400
|
+
for relative_path in (
|
|
401
|
+
additional_files if isinstance(additional_files, list) else []
|
|
402
|
+
):
|
|
403
|
+
additional_path = os.path.join(base_dir, relative_path)
|
|
404
|
+
if os.path.isfile(additional_path):
|
|
405
|
+
zip_file.write(
|
|
406
|
+
additional_path, os.path.join(data_id, relative_path)
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
zip_file.writestr("snapshot.json", flask.json.dumps(params.snapshot))
|
|
410
|
+
|
|
411
|
+
return utils_functions.send_file(project_folder, [export_vease_path], filename)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
@routes.route(
|
|
415
|
+
schemas_dict["import_project"]["route"],
|
|
416
|
+
methods=schemas_dict["import_project"]["methods"],
|
|
417
|
+
)
|
|
418
|
+
def import_project() -> flask.Response:
|
|
419
|
+
utils_functions.validate_request(flask.request, schemas_dict["import_project"])
|
|
420
|
+
if "file" not in flask.request.files:
|
|
421
|
+
flask.abort(400, "No .vease file provided under 'file'")
|
|
422
|
+
zip_file = flask.request.files["file"]
|
|
423
|
+
assert zip_file.filename is not None
|
|
424
|
+
filename = werkzeug.utils.secure_filename(os.path.basename(zip_file.filename))
|
|
425
|
+
if not filename.lower().endswith(".vease"):
|
|
426
|
+
flask.abort(400, "Uploaded file must be a .vease")
|
|
427
|
+
|
|
428
|
+
data_folder_path: str = flask.current_app.config["DATA_FOLDER_PATH"]
|
|
429
|
+
|
|
430
|
+
# 423 Locked bypass : remove stopped requests
|
|
431
|
+
if connection.scoped_session_registry:
|
|
432
|
+
connection.scoped_session_registry.remove()
|
|
433
|
+
if connection.engine:
|
|
434
|
+
connection.engine.dispose()
|
|
435
|
+
connection.engine = connection.session_factory = (
|
|
436
|
+
connection.scoped_session_registry
|
|
437
|
+
) = None
|
|
438
|
+
|
|
439
|
+
try:
|
|
440
|
+
if os.path.exists(data_folder_path):
|
|
441
|
+
shutil.rmtree(data_folder_path)
|
|
442
|
+
os.makedirs(data_folder_path, exist_ok=True)
|
|
443
|
+
except PermissionError:
|
|
444
|
+
flask.abort(423, "Project files are locked; cannot overwrite")
|
|
445
|
+
|
|
446
|
+
zip_file.stream.seek(0)
|
|
447
|
+
with zipfile.ZipFile(zip_file.stream) as zip_archive:
|
|
448
|
+
project_folder = os.path.abspath(data_folder_path)
|
|
449
|
+
for member in zip_archive.namelist():
|
|
450
|
+
target = os.path.abspath(
|
|
451
|
+
os.path.normpath(os.path.join(project_folder, member))
|
|
452
|
+
)
|
|
453
|
+
if not (
|
|
454
|
+
target == project_folder or target.startswith(project_folder + os.sep)
|
|
455
|
+
):
|
|
456
|
+
flask.abort(400, "Vease file contains unsafe paths")
|
|
457
|
+
zip_archive.extractall(project_folder)
|
|
458
|
+
|
|
459
|
+
database_root_path = os.path.join(project_folder, "project.db")
|
|
460
|
+
if not os.path.isfile(database_root_path):
|
|
461
|
+
flask.abort(400, "Missing project.db at project root")
|
|
462
|
+
|
|
463
|
+
connection.init_database(database_root_path, create_tables=False)
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
with get_session() as session:
|
|
467
|
+
rows = session.query(Data).all()
|
|
468
|
+
except Exception:
|
|
469
|
+
connection.init_database(database_root_path, create_tables=True)
|
|
470
|
+
with get_session() as session:
|
|
471
|
+
rows = session.query(Data).all()
|
|
472
|
+
|
|
473
|
+
with get_session() as session:
|
|
474
|
+
for data in rows:
|
|
475
|
+
data_path = geode_functions.data_file_path(data.id)
|
|
476
|
+
viewable_name = data.viewable_file
|
|
477
|
+
if viewable_name:
|
|
478
|
+
vpath = geode_functions.data_file_path(data.id, viewable_name)
|
|
479
|
+
if os.path.isfile(vpath):
|
|
480
|
+
continue
|
|
481
|
+
|
|
482
|
+
input_file = str(data.input_file or "")
|
|
483
|
+
if not input_file:
|
|
484
|
+
continue
|
|
485
|
+
|
|
486
|
+
input_full = geode_functions.data_file_path(data.id, input_file)
|
|
487
|
+
if not os.path.isfile(input_full):
|
|
488
|
+
continue
|
|
489
|
+
|
|
490
|
+
geode_object = geode_functions.geode_object_from_string(
|
|
491
|
+
data.geode_object
|
|
492
|
+
).load(input_full)
|
|
493
|
+
utils_functions.save_all_viewables_and_return_info(
|
|
494
|
+
geode_object, data, data_path
|
|
495
|
+
)
|
|
496
|
+
session.commit()
|
|
497
|
+
|
|
498
|
+
snapshot = {}
|
|
499
|
+
try:
|
|
500
|
+
raw = zip_archive.read("snapshot.json").decode("utf-8")
|
|
501
|
+
snapshot = flask.json.loads(raw)
|
|
502
|
+
except KeyError:
|
|
503
|
+
snapshot = {}
|
|
504
|
+
return flask.make_response({"snapshot": snapshot}, 200)
|