OpenGeodeWeb-Back 5.10.0rc6__tar.gz → 5.10.0rc9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {opengeodeweb_back-5.10.0rc6/src/OpenGeodeWeb_Back.egg-info → opengeodeweb_back-5.10.0rc9}/PKG-INFO +5 -1
  2. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/pyproject.toml +1 -1
  3. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/requirements.txt +9 -0
  4. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9/src/OpenGeodeWeb_Back.egg-info}/PKG-INFO +5 -1
  5. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/OpenGeodeWeb_Back.egg-info/SOURCES.txt +2 -0
  6. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/OpenGeodeWeb_Back.egg-info/requires.txt +4 -0
  7. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/app_config.py +11 -2
  8. opengeodeweb_back-5.10.0rc9/src/opengeodeweb_back/data.py +45 -0
  9. opengeodeweb_back-5.10.0rc9/src/opengeodeweb_back/database.py +19 -0
  10. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/geode_functions.py +24 -10
  11. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/blueprint_routes.py +24 -46
  12. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/models/blueprint_models.py +2 -8
  13. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/models/schemas/mesh_components.json +1 -11
  14. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json +0 -10
  15. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/polyhedron_attribute_names.json +0 -10
  16. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/texture_coordinates.json +1 -11
  17. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json +0 -10
  18. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/utils_functions.py +50 -24
  19. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/tests/test_models_routes.py +9 -3
  20. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/tests/test_routes.py +70 -113
  21. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/tests/test_utils_functions.py +61 -20
  22. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/LICENSE +0 -0
  23. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/README.md +0 -0
  24. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/setup.cfg +0 -0
  25. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/OpenGeodeWeb_Back.egg-info/dependency_links.txt +0 -0
  26. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/OpenGeodeWeb_Back.egg-info/top_level.txt +0 -0
  27. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/__init__.py +0 -0
  28. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/geode_objects.py +0 -0
  29. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/models/schemas/vtm_component_indices.json +0 -0
  30. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/allowed_files.json +0 -0
  31. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/allowed_objects.json +0 -0
  32. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/create_point.json +0 -0
  33. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.json +0 -0
  34. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/geographic_coordinate_systems.json +0 -0
  35. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/inspect_file.json +0 -0
  36. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/missing_files.json +0 -0
  37. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/ping.json +0 -0
  38. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/save_viewable_file.json +0 -0
  39. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/routes/schemas/upload_file.json +0 -0
  40. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/src/opengeodeweb_back/test_utils.py +0 -0
  41. {opengeodeweb_back-5.10.0rc6 → opengeodeweb_back-5.10.0rc9}/tests/test_geode_functions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenGeodeWeb-Back
3
- Version: 5.10.0rc6
3
+ Version: 5.10.0rc9
4
4
  Summary: OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem
5
5
  Author-email: Geode-solutions <team-web@geode-solutions.com>
6
6
  Project-URL: Homepage, https://github.com/Geode-solutions/OpenGeodeWeb-Back
@@ -17,8 +17,10 @@ Requires-Dist: click==8.2.1
17
17
  Requires-Dist: fastjsonschema==2.16.2
18
18
  Requires-Dist: flask[async]==3.0.3
19
19
  Requires-Dist: flask-cors==6.0.1
20
+ Requires-Dist: flask-sqlalchemy==3.1.1
20
21
  Requires-Dist: geode-common==33.9.0
21
22
  Requires-Dist: geode-viewables==3.2.0
23
+ Requires-Dist: greenlet==3.2.4
22
24
  Requires-Dist: itsdangerous==2.2.0
23
25
  Requires-Dist: jinja2==3.1.6
24
26
  Requires-Dist: markupsafe==3.0.2
@@ -27,6 +29,8 @@ Requires-Dist: opengeode-geosciences==9.2.2
27
29
  Requires-Dist: opengeode-geosciencesio==5.7.2
28
30
  Requires-Dist: opengeode-inspector==6.7.0
29
31
  Requires-Dist: opengeode-io==7.3.2
32
+ Requires-Dist: sqlalchemy==2.0.43
33
+ Requires-Dist: typing-extensions==4.15.0
30
34
  Requires-Dist: werkzeug==3.0.3
31
35
  Dynamic: license-file
32
36
 
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "OpenGeodeWeb-Back"
8
- version = "5.10.0-rc.6"
8
+ version = "5.10.0-rc.9"
9
9
  dynamic = ["dependencies"]
10
10
  authors = [
11
11
  { name="Geode-solutions", email="team-web@geode-solutions.com" },
@@ -17,12 +17,17 @@ flask[async]==3.0.3
17
17
  # -r requirements.in
18
18
  # flask
19
19
  # flask-cors
20
+ # flask-sqlalchemy
20
21
  flask-cors==6.0.1
21
22
  # via -r requirements.in
23
+ flask-sqlalchemy==3.1.1
24
+ # via -r requirements.in
22
25
  geode-common==33.9.0
23
26
  # via geode-viewables
24
27
  geode-viewables==3.2.0
25
28
  # via -r requirements.in
29
+ greenlet==3.2.4
30
+ # via sqlalchemy
26
31
  itsdangerous==2.2.0
27
32
  # via flask
28
33
  jinja2==3.1.6
@@ -54,6 +59,10 @@ opengeode-io==7.3.2
54
59
  # -r requirements.in
55
60
  # geode-viewables
56
61
  # opengeode-geosciencesio
62
+ sqlalchemy==2.0.43
63
+ # via flask-sqlalchemy
64
+ typing-extensions==4.15.0
65
+ # via sqlalchemy
57
66
  werkzeug==3.0.3
58
67
  # via
59
68
  # -r requirements.in
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenGeodeWeb-Back
3
- Version: 5.10.0rc6
3
+ Version: 5.10.0rc9
4
4
  Summary: OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem
5
5
  Author-email: Geode-solutions <team-web@geode-solutions.com>
6
6
  Project-URL: Homepage, https://github.com/Geode-solutions/OpenGeodeWeb-Back
@@ -17,8 +17,10 @@ Requires-Dist: click==8.2.1
17
17
  Requires-Dist: fastjsonschema==2.16.2
18
18
  Requires-Dist: flask[async]==3.0.3
19
19
  Requires-Dist: flask-cors==6.0.1
20
+ Requires-Dist: flask-sqlalchemy==3.1.1
20
21
  Requires-Dist: geode-common==33.9.0
21
22
  Requires-Dist: geode-viewables==3.2.0
23
+ Requires-Dist: greenlet==3.2.4
22
24
  Requires-Dist: itsdangerous==2.2.0
23
25
  Requires-Dist: jinja2==3.1.6
24
26
  Requires-Dist: markupsafe==3.0.2
@@ -27,6 +29,8 @@ Requires-Dist: opengeode-geosciences==9.2.2
27
29
  Requires-Dist: opengeode-geosciencesio==5.7.2
28
30
  Requires-Dist: opengeode-inspector==6.7.0
29
31
  Requires-Dist: opengeode-io==7.3.2
32
+ Requires-Dist: sqlalchemy==2.0.43
33
+ Requires-Dist: typing-extensions==4.15.0
30
34
  Requires-Dist: werkzeug==3.0.3
31
35
  Dynamic: license-file
32
36
 
@@ -9,6 +9,8 @@ src/OpenGeodeWeb_Back.egg-info/requires.txt
9
9
  src/OpenGeodeWeb_Back.egg-info/top_level.txt
10
10
  src/opengeodeweb_back/__init__.py
11
11
  src/opengeodeweb_back/app_config.py
12
+ src/opengeodeweb_back/data.py
13
+ src/opengeodeweb_back/database.py
12
14
  src/opengeodeweb_back/geode_functions.py
13
15
  src/opengeodeweb_back/geode_objects.py
14
16
  src/opengeodeweb_back/test_utils.py
@@ -4,8 +4,10 @@ click==8.2.1
4
4
  fastjsonschema==2.16.2
5
5
  flask[async]==3.0.3
6
6
  flask-cors==6.0.1
7
+ flask-sqlalchemy==3.1.1
7
8
  geode-common==33.9.0
8
9
  geode-viewables==3.2.0
10
+ greenlet==3.2.4
9
11
  itsdangerous==2.2.0
10
12
  jinja2==3.1.6
11
13
  markupsafe==3.0.2
@@ -14,4 +16,6 @@ opengeode-geosciences==9.2.2
14
16
  opengeode-geosciencesio==5.7.2
15
17
  opengeode-inspector==6.7.0
16
18
  opengeode-io==7.3.2
19
+ sqlalchemy==2.0.43
20
+ typing-extensions==4.15.0
17
21
  werkzeug==3.0.3
@@ -4,6 +4,7 @@ import time
4
4
 
5
5
  # Third party imports
6
6
  # Local application imports
7
+ from .database import DATABASE_FILENAME
7
8
 
8
9
 
9
10
  class Config(object):
@@ -15,6 +16,7 @@ class Config(object):
15
16
  REQUEST_COUNTER = 0
16
17
  LAST_REQUEST_TIME = time.time()
17
18
  LAST_PING_TIME = time.time()
19
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
18
20
 
19
21
 
20
22
  class ProdConfig(Config):
@@ -22,7 +24,10 @@ class ProdConfig(Config):
22
24
  ORIGINS = ""
23
25
  MINUTES_BEFORE_TIMEOUT = "1"
24
26
  SECONDS_BETWEEN_SHUTDOWNS = "10"
25
- DATA_FOLDER_PATH = "/data/"
27
+ DATA_FOLDER_PATH = "/data"
28
+ SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.abspath(
29
+ os.path.join(DATA_FOLDER_PATH, DATABASE_FILENAME)
30
+ )}"
26
31
 
27
32
 
28
33
  class DevConfig(Config):
@@ -30,4 +35,8 @@ class DevConfig(Config):
30
35
  ORIGINS = "*"
31
36
  MINUTES_BEFORE_TIMEOUT = "1"
32
37
  SECONDS_BETWEEN_SHUTDOWNS = "10"
33
- DATA_FOLDER_PATH = "./data/"
38
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
39
+ DATA_FOLDER_PATH = os.path.join(BASE_DIR, "data")
40
+ SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(
41
+ BASE_DIR, DATA_FOLDER_PATH, DATABASE_FILENAME
42
+ )}"
@@ -0,0 +1,45 @@
1
+ from sqlalchemy import String, JSON
2
+ from sqlalchemy.orm import Mapped, mapped_column
3
+ from .database import database, Base
4
+ import uuid
5
+
6
+
7
+ class Data(Base):
8
+ __tablename__ = "datas"
9
+
10
+ id: Mapped[str] = mapped_column(
11
+ String, primary_key=True, default=lambda: str(uuid.uuid4()).replace("-", "")
12
+ )
13
+ native_file_name: Mapped[str] = mapped_column(String, nullable=False)
14
+ viewable_file_name: Mapped[str] = mapped_column(String, nullable=False)
15
+ geode_object: Mapped[str] = mapped_column(String, nullable=False)
16
+
17
+ light_viewable: Mapped[str | None] = mapped_column(String, nullable=True)
18
+ input_file: Mapped[str | None] = mapped_column(String, nullable=True)
19
+ additional_files: Mapped[list[str] | None] = mapped_column(JSON, nullable=True)
20
+
21
+ @staticmethod
22
+ def create(
23
+ geode_object: str,
24
+ input_file: str | None = None,
25
+ additional_files: list[str] | None = None,
26
+ ) -> "Data":
27
+ input_file = input_file if input_file is not None else ""
28
+ additional_files = additional_files if additional_files is not None else []
29
+
30
+ data_entry = Data(
31
+ geode_object=geode_object,
32
+ input_file=input_file,
33
+ additional_files=additional_files,
34
+ native_file_name="",
35
+ viewable_file_name="",
36
+ light_viewable=None,
37
+ )
38
+
39
+ database.session.add(data_entry)
40
+ database.session.flush()
41
+ return data_entry
42
+
43
+ @staticmethod
44
+ def get(data_id: str) -> "Data | None":
45
+ return database.session.get(Data, data_id)
@@ -0,0 +1,19 @@
1
+ from flask import Flask
2
+ from flask_sqlalchemy import SQLAlchemy
3
+ from sqlalchemy.orm import DeclarativeBase
4
+
5
+ DATABASE_FILENAME = "project.db"
6
+
7
+
8
+ class Base(DeclarativeBase):
9
+ pass
10
+
11
+
12
+ database = SQLAlchemy(model_class=Base)
13
+
14
+
15
+ def initialize_database(app: Flask) -> SQLAlchemy:
16
+ database.init_app(app)
17
+ with app.app_context():
18
+ database.create_all()
19
+ return database
@@ -6,10 +6,13 @@ import opengeode_geosciences as og_gs # type: ignore
6
6
  import opengeode as og # type: ignore
7
7
  import werkzeug
8
8
  import flask
9
+ from typing import Any
9
10
 
10
11
  # Local application imports
11
12
  from .geode_objects import geode_objects_dict
12
13
  from . import utils_functions
14
+ from .data import Data
15
+ from .database import database
13
16
 
14
17
 
15
18
  def geode_object_value(geode_object: str):
@@ -45,21 +48,32 @@ def load(geode_object: str, file_absolute_path: str):
45
48
  return geode_object_value(geode_object)["load"](file_absolute_path)
46
49
 
47
50
 
48
- def data_file_path(data_id: str, filename: str) -> str:
51
+ def data_file_path(data_id: str, filename: str = "") -> str:
49
52
  data_folder_path = flask.current_app.config["DATA_FOLDER_PATH"]
50
- return os.path.join(
51
- data_folder_path,
52
- data_id,
53
- werkzeug.utils.secure_filename(filename),
54
- )
53
+ if filename:
54
+ return os.path.join(data_folder_path, data_id, filename)
55
+ return os.path.join(data_folder_path, data_id)
56
+
57
+
58
+ def load_data(data_id: str) -> Any:
59
+ data_entry = Data.get(data_id)
60
+ if not data_entry:
61
+ flask.abort(404, f"Data with id {data_id} not found")
62
+
63
+ file_absolute_path = data_file_path(data_id, data_entry.native_file_name)
64
+ return load(data_entry.geode_object, file_absolute_path)
65
+
55
66
 
67
+ def get_data_info(data_id: str) -> Data:
68
+ from .data import Data
56
69
 
57
- def load_data(geode_object: str, data_id: str, filename: str):
58
- file_absolute_path = data_file_path(data_id, filename)
59
- return load(geode_object, file_absolute_path)
70
+ data_entry = Data.get(data_id)
71
+ if not data_entry:
72
+ flask.abort(404, f"Data with id {data_id} not found")
73
+ return data_entry
60
74
 
61
75
 
62
- def upload_file_path(filename):
76
+ def upload_file_path(filename: str) -> str:
63
77
  upload_folder = flask.current_app.config["UPLOAD_FOLDER"]
64
78
  secure_filename = werkzeug.utils.secure_filename(filename)
65
79
  return os.path.abspath(os.path.join(upload_folder, secure_filename))
@@ -53,7 +53,7 @@ with open(
53
53
  def allowed_files():
54
54
  utils_functions.validate_request(flask.request, allowed_files_json)
55
55
  extensions = geode_functions.list_input_extensions(
56
- flask.request.json["supported_feature"]
56
+ flask.request.get_json()["supported_feature"]
57
57
  )
58
58
  return flask.make_response({"extensions": extensions}, 200)
59
59
 
@@ -99,10 +99,10 @@ def allowed_objects():
99
99
 
100
100
  utils_functions.validate_request(flask.request, allowed_objects_json)
101
101
  file_absolute_path = geode_functions.upload_file_path(
102
- flask.request.json["filename"]
102
+ flask.request.get_json()["filename"]
103
103
  )
104
104
  allowed_objects = geode_functions.list_geode_objects(
105
- file_absolute_path, flask.request.json["supported_feature"]
105
+ file_absolute_path, flask.request.get_json()["supported_feature"]
106
106
  )
107
107
  return flask.make_response({"allowed_objects": allowed_objects}, 200)
108
108
 
@@ -120,10 +120,10 @@ with open(
120
120
  )
121
121
  def missing_files():
122
122
  utils_functions.validate_request(flask.request, missing_files_json)
123
- file_path = geode_functions.upload_file_path(flask.request.json["filename"])
123
+ file_path = geode_functions.upload_file_path(flask.request.get_json()["filename"])
124
124
 
125
125
  additional_files = geode_functions.additional_files(
126
- flask.request.json["input_geode_object"],
126
+ flask.request.get_json()["input_geode_object"],
127
127
  file_path,
128
128
  )
129
129
 
@@ -167,7 +167,7 @@ with open(
167
167
  def crs_converter_geographic_coordinate_systems():
168
168
  utils_functions.validate_request(flask.request, geographic_coordinate_systems_json)
169
169
  infos = geode_functions.geographic_coordinate_systems(
170
- flask.request.json["input_geode_object"]
170
+ flask.request.get_json()["input_geode_object"]
171
171
  )
172
172
  crs_list = []
173
173
  for info in infos:
@@ -194,10 +194,12 @@ with open(
194
194
  def inspect_file():
195
195
  utils_functions.validate_request(flask.request, inspect_file_json)
196
196
 
197
- file_path = geode_functions.upload_file_path(flask.request.json["filename"])
198
- data = geode_functions.load(flask.request.json["input_geode_object"], file_path)
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
+ )
199
201
  class_inspector = geode_functions.inspect(
200
- flask.request.json["input_geode_object"], data
202
+ flask.request.get_json()["input_geode_object"], data
201
203
  )
202
204
  inspection_result = geode_functions.get_inspector_children(class_inspector)
203
205
  return flask.make_response({"inspection_result": inspection_result}, 200)
@@ -218,14 +220,14 @@ def geode_objects_and_output_extensions():
218
220
  utils_functions.validate_request(
219
221
  flask.request, geode_objects_and_output_extensions_json
220
222
  )
221
- file_path = geode_functions.upload_file_path(flask.request.json["filename"])
223
+ file_path = geode_functions.upload_file_path(flask.request.get_json()["filename"])
222
224
  data = geode_functions.load(
223
- flask.request.json["input_geode_object"],
225
+ flask.request.get_json()["input_geode_object"],
224
226
  file_path,
225
227
  )
226
228
  geode_objects_and_output_extensions = (
227
229
  geode_functions.geode_objects_output_extensions(
228
- flask.request.json["input_geode_object"], data
230
+ flask.request.get_json()["input_geode_object"], data
229
231
  )
230
232
  )
231
233
  return flask.make_response(
@@ -249,8 +251,8 @@ def save_viewable_file():
249
251
  utils_functions.validate_request(flask.request, save_viewable_file_json)
250
252
  return flask.make_response(
251
253
  utils_functions.generate_native_viewable_and_light_viewable_from_file(
252
- geode_object=flask.request.json["input_geode_object"],
253
- input_filename=flask.request.json["filename"],
254
+ geode_object=flask.request.get_json()["input_geode_object"],
255
+ input_filename=flask.request.get_json()["filename"],
254
256
  ),
255
257
  200,
256
258
  )
@@ -263,10 +265,10 @@ with open(os.path.join(schemas, "create_point.json"), "r") as file:
263
265
  @routes.route(create_point_json["route"], methods=create_point_json["methods"])
264
266
  def create_point():
265
267
  utils_functions.validate_request(flask.request, create_point_json)
266
- title = flask.request.json["title"]
267
- x = flask.request.json["x"]
268
- y = flask.request.json["y"]
269
- z = flask.request.json["z"]
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"]
270
272
  class_ = geode_functions.geode_object_class("PointSet3D")
271
273
  PointSet3D = class_.create()
272
274
  builder = geode_functions.create_builder("PointSet3D", PointSet3D)
@@ -290,14 +292,8 @@ with open(os.path.join(schemas, "texture_coordinates.json"), "r") as file:
290
292
  )
291
293
  def texture_coordinates():
292
294
  utils_functions.validate_request(flask.request, texture_coordinates_json)
293
- data = geode_functions.load_data(
294
- flask.request.json["input_geode_object"],
295
- flask.request.json["id"],
296
- flask.request.json["filename"],
297
- )
298
-
295
+ data = geode_functions.load_data(flask.request.get_json().get("id"))
299
296
  texture_coordinates = data.texture_manager().texture_names()
300
-
301
297
  return flask.make_response({"texture_coordinates": texture_coordinates}, 200)
302
298
 
303
299
 
@@ -314,14 +310,8 @@ with open(
314
310
  )
315
311
  def vertex_attribute_names():
316
312
  utils_functions.validate_request(flask.request, vertex_attribute_names_json)
317
- data = geode_functions.load_data(
318
- flask.request.json["input_geode_object"],
319
- flask.request.json["id"],
320
- flask.request.json["filename"],
321
- )
322
-
313
+ data = geode_functions.load_data(flask.request.get_json().get("id"))
323
314
  vertex_attribute_names = data.vertex_attribute_manager().attribute_names()
324
-
325
315
  return flask.make_response(
326
316
  {
327
317
  "vertex_attribute_names": vertex_attribute_names,
@@ -343,14 +333,8 @@ with open(
343
333
  )
344
334
  def polygon_attribute_names():
345
335
  utils_functions.validate_request(flask.request, polygon_attribute_names_json)
346
- data = geode_functions.load_data(
347
- flask.request.json["input_geode_object"],
348
- flask.request.json["id"],
349
- flask.request.json["filename"],
350
- )
351
-
336
+ data = geode_functions.load_data(flask.request.get_json().get("id"))
352
337
  polygon_attribute_names = data.polygon_attribute_manager().attribute_names()
353
-
354
338
  return flask.make_response(
355
339
  {
356
340
  "polygon_attribute_names": polygon_attribute_names,
@@ -372,14 +356,8 @@ with open(
372
356
  )
373
357
  def polyhedron_attribute_names():
374
358
  utils_functions.validate_request(flask.request, polyhedron_attribute_names_json)
375
- data = geode_functions.load_data(
376
- flask.request.json["input_geode_object"],
377
- flask.request.json["id"],
378
- flask.request.json["filename"],
379
- )
380
-
359
+ data = geode_functions.load_data(flask.request.get_json().get("id"))
381
360
  polyhedron_attribute_names = data.polyhedron_attribute_manager().attribute_names()
382
-
383
361
  return flask.make_response(
384
362
  {
385
363
  "polyhedron_attribute_names": polyhedron_attribute_names,
@@ -20,7 +20,7 @@ def uuid_to_flat_index():
20
20
  utils_functions.validate_request(flask.request, vtm_component_indices_json)
21
21
 
22
22
  vtm_file_path = geode_functions.data_file_path(
23
- flask.request.json["id"], "viewable.vtm"
23
+ flask.request.get_json().get("id"), "viewable.vtm"
24
24
  )
25
25
  tree = ET.parse(vtm_file_path)
26
26
  root = tree.find("vtkMultiBlockDataSet")
@@ -49,12 +49,6 @@ with open(os.path.join(schemas, "mesh_components.json"), "r") as file:
49
49
  @routes.route(mesh_components_json["route"], methods=mesh_components_json["methods"])
50
50
  def extract_uuids_endpoint():
51
51
  utils_functions.validate_request(flask.request, mesh_components_json)
52
-
53
- model = geode_functions.load_data(
54
- flask.request.json["geode_object"],
55
- flask.request.json["id"],
56
- flask.request.json["filename"],
57
- )
58
-
52
+ model = geode_functions.load_data(flask.request.get_json().get("id"))
59
53
  uuid_dict = extract_model_uuids(model)
60
54
  return flask.make_response({"uuid_dict": uuid_dict}, 200)
@@ -8,20 +8,10 @@
8
8
  "id": {
9
9
  "type": "string",
10
10
  "minLength": 1
11
- },
12
- "filename": {
13
- "type": "string",
14
- "minLength": 1
15
- },
16
- "geode_object": {
17
- "type": "string",
18
- "minLength": 1
19
11
  }
20
12
  },
21
13
  "required": [
22
- "id",
23
- "filename",
24
- "geode_object"
14
+ "id"
25
15
  ],
26
16
  "additionalProperties": false
27
17
  }
@@ -5,22 +5,12 @@
5
5
  ],
6
6
  "type": "object",
7
7
  "properties": {
8
- "input_geode_object": {
9
- "type": "string",
10
- "minLength": 1
11
- },
12
- "filename": {
13
- "type": "string",
14
- "minLength": 1
15
- },
16
8
  "id": {
17
9
  "type": "string",
18
10
  "minLength": 1
19
11
  }
20
12
  },
21
13
  "required": [
22
- "input_geode_object",
23
- "filename",
24
14
  "id"
25
15
  ],
26
16
  "additionalProperties": false
@@ -5,22 +5,12 @@
5
5
  ],
6
6
  "type": "object",
7
7
  "properties": {
8
- "input_geode_object": {
9
- "type": "string",
10
- "minLength": 1
11
- },
12
- "filename": {
13
- "type": "string",
14
- "minLength": 1
15
- },
16
8
  "id": {
17
9
  "type": "string",
18
10
  "minLength": 1
19
11
  }
20
12
  },
21
13
  "required": [
22
- "input_geode_object",
23
- "filename",
24
14
  "id"
25
15
  ],
26
16
  "additionalProperties": false
@@ -5,23 +5,13 @@
5
5
  ],
6
6
  "type": "object",
7
7
  "properties": {
8
- "input_geode_object": {
9
- "type": "string",
10
- "minLength": 1
11
- },
12
- "filename": {
13
- "type": "string",
14
- "minLength": 1
15
- },
16
8
  "id": {
17
9
  "type": "string",
18
10
  "minLength": 1
19
11
  }
20
12
  },
21
13
  "required": [
22
- "input_geode_object",
23
- "id",
24
- "filename"
14
+ "id"
25
15
  ],
26
16
  "additionalProperties": false
27
17
  }
@@ -5,22 +5,12 @@
5
5
  ],
6
6
  "type": "object",
7
7
  "properties": {
8
- "input_geode_object": {
9
- "type": "string",
10
- "minLength": 1
11
- },
12
- "filename": {
13
- "type": "string",
14
- "minLength": 1
15
- },
16
8
  "id": {
17
9
  "type": "string",
18
10
  "minLength": 1
19
11
  }
20
12
  },
21
13
  "required": [
22
- "input_geode_object",
23
- "filename",
24
14
  "id"
25
15
  ],
26
16
  "additionalProperties": false
@@ -2,7 +2,6 @@
2
2
  import os
3
3
  import threading
4
4
  import time
5
- import uuid
6
5
  import zipfile
7
6
  from collections.abc import Callable
8
7
  from typing import Any
@@ -17,6 +16,8 @@ import werkzeug
17
16
 
18
17
  # Local application imports
19
18
  from . import geode_functions
19
+ from .data import Data
20
+ from .database import database
20
21
 
21
22
 
22
23
  def increment_request_counter(current_app: flask.Flask) -> None:
@@ -152,17 +153,28 @@ def handle_exception(exception: HTTPException) -> flask.Response:
152
153
  return response
153
154
 
154
155
 
155
- def create_unique_data_folder() -> tuple[str, str]:
156
+ def create_data_folder_from_id(data_id: str) -> str:
156
157
  base_data_folder = flask.current_app.config["DATA_FOLDER_PATH"]
157
- generated_id = str(uuid.uuid4()).replace("-", "")
158
- data_path = os.path.join(base_data_folder, generated_id)
158
+ data_path = os.path.join(base_data_folder, data_id)
159
159
  os.makedirs(data_path, exist_ok=True)
160
- return generated_id, data_path
160
+ return data_path
161
161
 
162
162
 
163
163
  def save_all_viewables_and_return_info(
164
- geode_object, data, generated_id, data_path, additional_files=None
165
- ):
164
+ geode_object: str,
165
+ data: Any,
166
+ input_file: str,
167
+ additional_files: list[str] | None = None,
168
+ ) -> dict[str, Any]:
169
+ if additional_files is None:
170
+ additional_files = []
171
+
172
+ data_entry = Data.create(
173
+ geode_object=geode_object,
174
+ input_file=input_file,
175
+ additional_files=additional_files,
176
+ )
177
+ data_path = create_data_folder_from_id(data_entry.id)
166
178
  saved_native_file_path = geode_functions.save(
167
179
  geode_object,
168
180
  data,
@@ -177,28 +189,40 @@ def save_all_viewables_and_return_info(
177
189
  )
178
190
  with open(saved_light_viewable_file_path, "rb") as f:
179
191
  binary_light_viewable = f.read()
192
+ data_entry.native_file_name = os.path.basename(saved_native_file_path[0])
193
+ data_entry.viewable_file_name = os.path.basename(saved_viewable_file_path)
194
+ data_entry.light_viewable = os.path.basename(saved_light_viewable_file_path)
195
+
196
+ database.session.commit()
180
197
 
181
198
  return {
182
- "name": data.name(),
183
- "native_file_name": os.path.basename(saved_native_file_path[0]),
184
- "viewable_file_name": os.path.basename(saved_viewable_file_path),
185
- "id": generated_id,
199
+ "native_file_name": data_entry.native_file_name,
200
+ "viewable_file_name": data_entry.viewable_file_name,
201
+ "id": data_entry.id,
186
202
  "object_type": geode_functions.get_object_type(geode_object),
187
203
  "binary_light_viewable": binary_light_viewable.decode("utf-8"),
188
- "geode_object": geode_object,
189
- "input_files": additional_files or [],
204
+ "geode_object": data_entry.geode_object,
205
+ "input_files": data_entry.input_file,
206
+ "additional_files": data_entry.additional_files,
190
207
  }
191
208
 
192
209
 
193
- def generate_native_viewable_and_light_viewable_from_object(geode_object, data):
194
- generated_id, data_path = create_unique_data_folder()
195
- return save_all_viewables_and_return_info(
196
- geode_object, data, generated_id, data_path
197
- )
210
+ def generate_native_viewable_and_light_viewable_from_object(
211
+ geode_object: str, data: Any
212
+ ) -> dict[str, Any]:
213
+ return save_all_viewables_and_return_info(geode_object, data, input_file="")
198
214
 
199
215
 
200
- def generate_native_viewable_and_light_viewable_from_file(geode_object, input_filename):
201
- generated_id, data_path = create_unique_data_folder()
216
+ def generate_native_viewable_and_light_viewable_from_file(
217
+ geode_object: str, input_filename: str
218
+ ) -> dict[str, Any]:
219
+ temp_data_entry = Data.create(
220
+ geode_object=geode_object,
221
+ input_file=input_filename,
222
+ additional_files=[],
223
+ )
224
+
225
+ data_path = create_data_folder_from_id(temp_data_entry.id)
202
226
 
203
227
  full_input_filename = geode_functions.upload_file_path(input_filename)
204
228
  copied_full_path = os.path.join(
@@ -206,7 +230,7 @@ def generate_native_viewable_and_light_viewable_from_file(geode_object, input_fi
206
230
  )
207
231
  shutil.copy2(full_input_filename, copied_full_path)
208
232
 
209
- additional_files_copied = []
233
+ additional_files_copied: list[str] = []
210
234
  additional = geode_functions.additional_files(geode_object, full_input_filename)
211
235
  for additional_file in additional.mandatory_files + additional.optional_files:
212
236
  if additional_file.is_missing:
@@ -221,12 +245,14 @@ def generate_native_viewable_and_light_viewable_from_file(geode_object, input_fi
221
245
  shutil.copy2(source_path, dest_path)
222
246
  additional_files_copied.append(additional_file.filename)
223
247
 
224
- data = geode_functions.load_data(geode_object, generated_id, input_filename)
248
+ data = geode_functions.load(geode_object, copied_full_path)
249
+
250
+ database.session.delete(temp_data_entry)
251
+ database.session.flush()
225
252
 
226
253
  return save_all_viewables_and_return_info(
227
254
  geode_object,
228
255
  data,
229
- generated_id,
230
- data_path,
256
+ input_file=input_filename,
231
257
  additional_files=additional_files_copied,
232
258
  )
@@ -3,6 +3,8 @@ import shutil
3
3
  import flask
4
4
 
5
5
  from src.opengeodeweb_back import geode_functions
6
+ from src.opengeodeweb_back.data import Data
7
+ from src.opengeodeweb_back.database import database
6
8
 
7
9
 
8
10
  def test_model_mesh_components(client, test_id):
@@ -28,14 +30,18 @@ def test_model_mesh_components(client, test_id):
28
30
 
29
31
  def test_extract_brep_uuids(client, test_id):
30
32
  route = "/models/mesh_components"
31
-
32
33
  brep_filename = "cube.og_brep"
33
- json_data = {"id": test_id, "geode_object": "BRep", "filename": brep_filename}
34
34
 
35
35
  with client.application.app_context():
36
- data_path = geode_functions.data_file_path(json_data["id"], brep_filename)
36
+ data_entry = Data.create(geode_object="BRep", input_file=brep_filename)
37
+ data_entry.native_file_name = brep_filename
38
+ database.session.commit()
39
+
40
+ data_path = geode_functions.data_file_path(data_entry.id, brep_filename)
37
41
  os.makedirs(os.path.dirname(data_path), exist_ok=True)
38
42
  shutil.copy(f"./tests/data/{brep_filename}", data_path)
43
+
44
+ json_data = {"id": data_entry.id}
39
45
  response = client.post(route, json=json_data)
40
46
 
41
47
  assert response.status_code == 200
@@ -6,7 +6,9 @@ import shutil
6
6
  from werkzeug.datastructures import FileStorage
7
7
 
8
8
  # Local application imports
9
- from src.opengeodeweb_back import geode_functions, geode_objects, test_utils
9
+ from src.opengeodeweb_back import geode_functions, test_utils
10
+ from src.opengeodeweb_back.data import Data
11
+ from src.opengeodeweb_back.database import database
10
12
 
11
13
 
12
14
  def test_allowed_files(client):
@@ -151,13 +153,11 @@ def test_save_viewable_file(client):
151
153
  # Normal test with filename 'corbi.og_brep'
152
154
  response = client.post(route, json=get_full_data())
153
155
  assert response.status_code == 200
154
- name = response.json["name"]
155
- assert type(name) is str
156
156
  native_file_name = response.json["native_file_name"]
157
157
  assert type(native_file_name) is str
158
158
  viewable_file_name = response.json["viewable_file_name"]
159
159
  assert type(viewable_file_name) is str
160
- id = response.json["id"]
160
+ id = response.json.get("id")
161
161
  assert type(id) is str
162
162
  object_type = response.json["object_type"]
163
163
  assert type(object_type) is str
@@ -171,17 +171,18 @@ def test_save_viewable_file(client):
171
171
 
172
172
  def test_texture_coordinates(client, test_id):
173
173
  with client.application.app_context():
174
- data_path = geode_functions.data_file_path(test_id, "hat.vtp")
174
+ data = Data.create(geode_object="PolygonalSurface3D", input_file="hat.vtp")
175
+ data.native_file_name = "hat.vtp"
176
+ database.session.commit()
177
+
178
+ data_path = geode_functions.data_file_path(data.id, "hat.vtp")
179
+ print(data_path)
175
180
  os.makedirs(os.path.dirname(data_path), exist_ok=True)
176
181
  shutil.copy("./tests/data/hat.vtp", data_path)
177
182
 
178
183
  response = client.post(
179
184
  "/texture_coordinates",
180
- json={
181
- "input_geode_object": "PolygonalSurface3D",
182
- "id": test_id,
183
- "filename": "hat.vtp",
184
- },
185
+ json={"id": data.id},
185
186
  )
186
187
  assert response.status_code == 200
187
188
  texture_coordinates = response.json["texture_coordinates"]
@@ -192,119 +193,63 @@ def test_texture_coordinates(client, test_id):
192
193
 
193
194
  def test_vertex_attribute_names(client, test_id):
194
195
  route = f"/vertex_attribute_names"
195
- for geode_object, value in geode_objects.geode_objects_dict().items():
196
- if value["object_type"] == "mesh":
197
- input_extensions = geode_functions.geode_object_input_extensions(
198
- geode_object
199
- )
200
- if "elements" in value:
201
- elements = geode_functions.get_elements(geode_object)
202
- if "points" in elements:
203
- for input_extension in input_extensions:
204
- if (
205
- geode_functions.is_loadable(
206
- geode_object,
207
- os.path.join("./data", f"test.{input_extension}"),
208
- )
209
- > 0.0
210
- ):
211
-
212
- def get_full_data():
213
- return {
214
- "input_geode_object": geode_object,
215
- "id": test_id,
216
- "filename": f"test.{input_extension}",
217
- }
218
-
219
- response = client.post(route, json=get_full_data())
220
- assert response.status_code == 200
221
- vertex_attribute_names = response.json[
222
- "vertex_attribute_names"
223
- ]
224
- assert type(vertex_attribute_names) is list
225
- for vertex_attribute_name in vertex_attribute_names:
226
- assert type(vertex_attribute_name) is str
227
196
 
228
- # Test all params
229
- test_utils.test_route_wrong_params(client, route, get_full_data)
197
+ with client.application.app_context():
198
+ data = Data.create(geode_object="PolygonalSurface3D", input_file="test.vtp")
199
+ data.native_file_name = "test.vtp"
200
+ database.session.commit()
201
+
202
+ data_path = geode_functions.data_file_path(data.id, "test.vtp")
203
+ os.makedirs(os.path.dirname(data_path), exist_ok=True)
204
+ if os.path.exists("./tests/data/hat.vtp"):
205
+ shutil.copy("./tests/data/hat.vtp", data_path)
206
+
207
+ response = client.post(route, json={"id": data.id})
208
+ assert response.status_code == 200
209
+ vertex_attribute_names = response.json["vertex_attribute_names"]
210
+ assert type(vertex_attribute_names) is list
211
+ for vertex_attribute_name in vertex_attribute_names:
212
+ assert type(vertex_attribute_name) is str
230
213
 
231
214
 
232
215
  def test_polygon_attribute_names(client, test_id):
233
216
  route = f"/polygon_attribute_names"
234
- for geode_object, value in geode_objects.geode_objects_dict().items():
235
- if value["object_type"] == "mesh":
236
- input_extensions = geode_functions.geode_object_input_extensions(
237
- geode_object
238
- )
239
- if "elements" in value:
240
- elements = geode_functions.get_elements(geode_object)
241
- if "polygons" in elements:
242
- for input_extension in input_extensions:
243
- if (
244
- geode_functions.is_loadable(
245
- geode_object,
246
- os.path.join("./data", f"test.{input_extension}"),
247
- )
248
- > 0.0
249
- ):
250
-
251
- def get_full_data():
252
- return {
253
- "input_geode_object": geode_object,
254
- "id": test_id,
255
- "filename": f"test.{input_extension}",
256
- }
257
-
258
- response = client.post(route, json=get_full_data())
259
- assert response.status_code == 200
260
- polygon_attribute_names = response.json[
261
- "polygon_attribute_names"
262
- ]
263
- assert type(polygon_attribute_names) is list
264
- for polygon_attribute_name in polygon_attribute_names:
265
- assert type(polygon_attribute_name) is str
266
217
 
267
- # Test all params
268
- test_utils.test_route_wrong_params(client, route, get_full_data)
218
+ with client.application.app_context():
219
+ data = Data.create(geode_object="PolygonalSurface3D", input_file="test.vtp")
220
+ data.native_file_name = "test.vtp"
221
+ database.session.commit()
222
+
223
+ data_path = geode_functions.data_file_path(data.id, "test.vtp")
224
+ os.makedirs(os.path.dirname(data_path), exist_ok=True)
225
+ shutil.copy("./tests/data/test.vtp", data_path)
226
+
227
+ response = client.post(route, json={"id": data.id})
228
+ assert response.status_code == 200
229
+ polygon_attribute_names = response.json["polygon_attribute_names"]
230
+ assert type(polygon_attribute_names) is list
231
+ for polygon_attribute_name in polygon_attribute_names:
232
+ assert type(polygon_attribute_name) is str
269
233
 
270
234
 
271
235
  def test_polyhedron_attribute_names(client, test_id):
272
236
  route = f"/polyhedron_attribute_names"
273
- for geode_object, value in geode_objects.geode_objects_dict().items():
274
- if value["object_type"] == "mesh":
275
- input_extensions = geode_functions.geode_object_input_extensions(
276
- geode_object
277
- )
278
- if "elements" in value:
279
- elements = geode_functions.get_elements(geode_object)
280
- if "polyhedrons" in elements:
281
- for input_extension in input_extensions:
282
- if (
283
- geode_functions.is_loadable(
284
- geode_object,
285
- os.path.join("./data", f"test.{input_extension}"),
286
- )
287
- > 0.0
288
- ):
289
-
290
- def get_full_data():
291
- return {
292
- "input_geode_object": geode_object,
293
- "id": test_id,
294
- "filename": f"test.{input_extension}",
295
- }
296
-
297
- response = client.post(route, json=get_full_data())
298
- assert response.status_code == 200
299
- polyhedron_attribute_names = response.json[
300
- "polyhedron_attribute_names"
301
- ]
302
- assert type(polyhedron_attribute_names) is list
303
- for polyhedron_attribute_name in polyhedron_attribute_names:
304
- assert type(polyhedron_attribute_name) is str
305
237
 
306
- # Test all params
307
- test_utils.test_route_wrong_params(client, route, get_full_data)
238
+ with client.application.app_context():
239
+ data = Data.create(geode_object="PolyhedralSolid3D", input_file="test.vtu")
240
+ data.native_file_name = "test.vtu"
241
+ database.session.commit()
242
+
243
+ data_path = geode_functions.data_file_path(data.id, "test.vtu")
244
+ os.makedirs(os.path.dirname(data_path), exist_ok=True)
245
+ shutil.copy("./tests/data/test.vtu", data_path)
246
+
247
+ response = client.post(route, json={"id": data.id})
248
+ assert response.status_code == 200
249
+ polyhedron_attribute_names = response.json["polyhedron_attribute_names"]
250
+ assert type(polyhedron_attribute_names) is list
251
+ for polyhedron_attribute_name in polyhedron_attribute_names:
252
+ assert type(polyhedron_attribute_name) is str
308
253
 
309
254
 
310
255
  def test_create_point(client):
@@ -316,8 +261,20 @@ def test_create_point(client):
316
261
  assert response.status_code == 200
317
262
  viewable_file_name = response.json["viewable_file_name"]
318
263
  assert type(viewable_file_name) is str
319
- id = response.json["id"]
264
+ id = response.json.get("id")
320
265
  assert type(id) is str
321
266
 
322
267
  # Test all params
323
268
  test_utils.test_route_wrong_params(client, route, get_full_data)
269
+
270
+
271
+ def test_database_uri_path(client):
272
+ app = client.application
273
+ with app.app_context():
274
+ base_dir = os.path.abspath(os.path.dirname(__file__))
275
+ expected_db_path = os.path.join(base_dir, "data", "project.db")
276
+ expected_uri = f"sqlite:///{expected_db_path}"
277
+
278
+ assert app.config["SQLALCHEMY_DATABASE_URI"] == expected_uri
279
+
280
+ assert os.path.exists(expected_db_path)
@@ -5,8 +5,11 @@ import os
5
5
  # Third party imports
6
6
  import flask
7
7
  import shutil
8
+ import uuid
8
9
 
9
10
  # Local application imports
11
+ from src.opengeodeweb_back.database import database
12
+ from src.opengeodeweb_back.data import Data
10
13
  from src.opengeodeweb_back import geode_functions, utils_functions
11
14
 
12
15
 
@@ -72,15 +75,15 @@ def test_handle_exception(client):
72
75
  assert type(data["code"]) is int
73
76
 
74
77
 
75
- def test_create_unique_data_folder(client):
78
+ def test_create_data_folder_from_id(client):
76
79
  app = client.application
77
80
  with app.app_context():
78
- generated_id, data_path = utils_functions.create_unique_data_folder()
79
- assert isinstance(generated_id, str)
80
- assert re.fullmatch(r"[0-9a-f]{32}", generated_id)
81
+ test_id = str(uuid.uuid4()).replace("-", "")
82
+ data_path = utils_functions.create_data_folder_from_id(test_id)
83
+ assert isinstance(data_path, str)
81
84
  assert os.path.exists(data_path)
82
85
  assert data_path.startswith(flask.current_app.config["DATA_FOLDER_PATH"])
83
- assert generated_id in data_path
86
+ assert test_id in data_path
84
87
  shutil.rmtree(data_path, ignore_errors=True)
85
88
  assert not os.path.exists(data_path)
86
89
 
@@ -88,24 +91,64 @@ def test_create_unique_data_folder(client):
88
91
  def test_save_all_viewables_and_return_info(client):
89
92
  app = client.application
90
93
  with app.app_context():
94
+ base_dir = os.path.abspath(os.path.dirname(__file__))
95
+ expected_db_path = os.path.join(base_dir, "data", "project.db")
96
+ expected_uri = f"sqlite:///{expected_db_path}"
97
+
98
+ assert app.config["SQLALCHEMY_DATABASE_URI"] == expected_uri
99
+ assert os.path.exists(expected_db_path)
100
+
91
101
  geode_object = "BRep"
92
102
  data = geode_functions.load(geode_object, "./tests/data/test.og_brep")
93
- generated_id, data_path = utils_functions.create_unique_data_folder()
103
+ input_file = "test.og_brep"
94
104
  additional_files = ["additional_file.txt"]
95
105
 
96
106
  result = utils_functions.save_all_viewables_and_return_info(
97
- geode_object, data, generated_id, data_path, additional_files
107
+ geode_object, data, input_file, additional_files
98
108
  )
99
109
 
100
- assert isinstance(result, dict)
101
- assert result["name"] == data.name()
102
- assert result["native_file_name"].startswith("native.")
103
- assert result["viewable_file_name"].endswith(".vtm")
104
- assert re.match(r"[0-9a-f]{32}", result["id"])
105
- assert isinstance(result["object_type"], str)
106
- assert isinstance(result["binary_light_viewable"], str)
107
- assert result["geode_object"] == geode_object
108
- assert result["input_files"] == additional_files
110
+ assert isinstance(result, dict)
111
+ assert result["native_file_name"].startswith("native.")
112
+ assert result["viewable_file_name"].endswith(".vtm")
113
+ assert isinstance(result["id"], str)
114
+ assert len(result["id"]) == 32
115
+ assert re.match(r"[0-9a-f]{32}", result["id"])
116
+ assert isinstance(result["object_type"], str)
117
+ assert isinstance(result["binary_light_viewable"], str)
118
+ assert result["geode_object"] == geode_object
119
+ assert result["input_files"] == input_file
120
+
121
+ db_entry = Data.get(result["id"])
122
+ assert db_entry is not None
123
+ assert db_entry.native_file_name == result["native_file_name"]
124
+ assert db_entry.viewable_file_name == result["viewable_file_name"]
125
+ assert db_entry.geode_object == geode_object
126
+ assert db_entry.input_file == input_file
127
+ assert db_entry.additional_files == additional_files
128
+
129
+ expected_data_path = os.path.join(app.config["DATA_FOLDER_PATH"], result["id"])
130
+ assert os.path.exists(expected_data_path)
131
+
132
+
133
+ def test_save_all_viewables_commits_to_db(client):
134
+ app = client.application
135
+ with app.app_context():
136
+ geode_object = "BRep"
137
+ data = geode_functions.load(geode_object, "./tests/data/test.og_brep")
138
+ input_file = "test.og_brep"
139
+ result = utils_functions.save_all_viewables_and_return_info(
140
+ geode_object, data, input_file
141
+ )
142
+ data_id = result["id"]
143
+ db_entry_before = Data.get(data_id)
144
+ assert db_entry_before is not None
145
+ assert db_entry_before.native_file_name == result["native_file_name"]
146
+ database.session.rollback()
147
+ db_entry_after = Data.get(data_id)
148
+ assert (
149
+ db_entry_after is not None
150
+ ), "database.session.commit() was not called - entry missing after rollback"
151
+ assert db_entry_after.native_file_name == result["native_file_name"]
109
152
 
110
153
 
111
154
  def test_generate_native_viewable_and_light_viewable_from_object(client):
@@ -121,7 +164,6 @@ def test_generate_native_viewable_and_light_viewable_from_object(client):
121
164
  )
122
165
 
123
166
  assert isinstance(result, dict)
124
- assert isinstance(result["name"], str)
125
167
  assert isinstance(result["native_file_name"], str)
126
168
  assert result["native_file_name"].startswith("native.")
127
169
  assert isinstance(result["viewable_file_name"], str)
@@ -130,7 +172,7 @@ def test_generate_native_viewable_and_light_viewable_from_object(client):
130
172
  assert re.match(r"[0-9a-f]{32}", result["id"])
131
173
  assert isinstance(result["object_type"], str)
132
174
  assert isinstance(result["binary_light_viewable"], str)
133
- assert result["input_files"] == []
175
+ assert result["input_files"] == ""
134
176
 
135
177
 
136
178
  def test_generate_native_viewable_and_light_viewable_from_file(client):
@@ -144,7 +186,6 @@ def test_generate_native_viewable_and_light_viewable_from_file(client):
144
186
  )
145
187
 
146
188
  assert isinstance(result, dict)
147
- assert isinstance(result["name"], str)
148
189
  assert isinstance(result["native_file_name"], str)
149
190
  assert result["native_file_name"].startswith("native.")
150
191
  assert isinstance(result["viewable_file_name"], str)
@@ -153,4 +194,4 @@ def test_generate_native_viewable_and_light_viewable_from_file(client):
153
194
  assert re.match(r"[0-9a-f]{32}", result["id"])
154
195
  assert isinstance(result["object_type"], str)
155
196
  assert isinstance(result["binary_light_viewable"], str)
156
- assert isinstance(result["input_files"], list)
197
+ assert isinstance(result["input_files"], str)