pyarchinit-mini 1.9.28__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.
- pyarchinit_mini/__init__.py +40 -0
- pyarchinit_mini/api/__init__.py +92 -0
- pyarchinit_mini/api/auth.py +312 -0
- pyarchinit_mini/api/dependencies.py +63 -0
- pyarchinit_mini/api/graphml.py +160 -0
- pyarchinit_mini/api/inventario.py +107 -0
- pyarchinit_mini/api/schemas.py +186 -0
- pyarchinit_mini/api/site.py +220 -0
- pyarchinit_mini/api/us.py +107 -0
- pyarchinit_mini/cli/__init__.py +7 -0
- pyarchinit_mini/cli/export_import_cli.py +289 -0
- pyarchinit_mini/cli/extended_matrix_import.py +101 -0
- pyarchinit_mini/cli/graphml_cli.py +219 -0
- pyarchinit_mini/cli/harris_import.py +574 -0
- pyarchinit_mini/cli/harris_template.py +323 -0
- pyarchinit_mini/cli/migrate.py +202 -0
- pyarchinit_mini/cli/pyarchinit_import_export_cli.py +428 -0
- pyarchinit_mini/cli_interface/__init__.py +1 -0
- pyarchinit_mini/cli_interface/cli_app.py +529 -0
- pyarchinit_mini/config/__init__.py +0 -0
- pyarchinit_mini/config/connection_manager.py +286 -0
- pyarchinit_mini/config/em_node_config_manager.py +452 -0
- pyarchinit_mini/config/em_node_types.yaml +349 -0
- pyarchinit_mini/database/__init__.py +13 -0
- pyarchinit_mini/database/connection.py +168 -0
- pyarchinit_mini/database/database_creator.py +290 -0
- pyarchinit_mini/database/manager.py +231 -0
- pyarchinit_mini/database/migration_scripts/__init__.py +7 -0
- pyarchinit_mini/database/migration_scripts/add_file_path.py +152 -0
- pyarchinit_mini/database/migration_scripts/add_i18n_columns.py +312 -0
- pyarchinit_mini/database/migration_scripts/add_tipo_documento.py +154 -0
- pyarchinit_mini/database/migration_scripts/change_us_area_to_text.py +321 -0
- pyarchinit_mini/database/migration_scripts/change_us_area_to_text_simple.py +230 -0
- pyarchinit_mini/database/migrations.py +232 -0
- pyarchinit_mini/database/postgres_installer.py +375 -0
- pyarchinit_mini/database/schemas.py +177 -0
- pyarchinit_mini/desktop_gui/__init__.py +51 -0
- pyarchinit_mini/desktop_gui/analytics_dialog.py +228 -0
- pyarchinit_mini/desktop_gui/assets/logo.png +0 -0
- pyarchinit_mini/desktop_gui/dialogs.py +1984 -0
- pyarchinit_mini/desktop_gui/excel_import_dialog.py +380 -0
- pyarchinit_mini/desktop_gui/export_import_dialog.py +313 -0
- pyarchinit_mini/desktop_gui/graphml_export_dialog.py +221 -0
- pyarchinit_mini/desktop_gui/gui_app.py +106 -0
- pyarchinit_mini/desktop_gui/harris_matrix_editor.py +970 -0
- pyarchinit_mini/desktop_gui/i18n.py +191 -0
- pyarchinit_mini/desktop_gui/icons.py +70 -0
- pyarchinit_mini/desktop_gui/inventario_dialog_extended.py +966 -0
- pyarchinit_mini/desktop_gui/main_window.py +1826 -0
- pyarchinit_mini/desktop_gui/media_manager_advanced.py +141 -0
- pyarchinit_mini/desktop_gui/postgres_installer_dialog.py +357 -0
- pyarchinit_mini/desktop_gui/pyarchinit_import_export_dialog.py +585 -0
- pyarchinit_mini/desktop_gui/thesaurus_dialog.py +463 -0
- pyarchinit_mini/desktop_gui/us_dialog_extended.py +2122 -0
- pyarchinit_mini/dto/__init__.py +16 -0
- pyarchinit_mini/dto/inventario_dto.py +57 -0
- pyarchinit_mini/dto/site_dto.py +62 -0
- pyarchinit_mini/dto/us_dto.py +237 -0
- pyarchinit_mini/exceptions.py +23 -0
- pyarchinit_mini/graphml_converter/__init__.py +47 -0
- pyarchinit_mini/graphml_converter/converter.py +343 -0
- pyarchinit_mini/graphml_converter/dot_parser.py +1331 -0
- pyarchinit_mini/graphml_converter/em_palette.py +355 -0
- pyarchinit_mini/graphml_converter/graphml_builder.py +657 -0
- pyarchinit_mini/graphml_converter/graphml_exporter.py +1048 -0
- pyarchinit_mini/graphml_converter/pure_networkx_exporter.py +719 -0
- pyarchinit_mini/graphml_converter/svg_resources.py +244 -0
- pyarchinit_mini/graphml_converter/templates/EM_palette.graphml +658 -0
- pyarchinit_mini/graphml_converter/x11_colors.py +678 -0
- pyarchinit_mini/graphml_converter/yed_template.py +365 -0
- pyarchinit_mini/harris_matrix/__init__.py +11 -0
- pyarchinit_mini/harris_matrix/enhanced_visualizer.py +465 -0
- pyarchinit_mini/harris_matrix/matrix_generator.py +1244 -0
- pyarchinit_mini/harris_matrix/matrix_visualizer.py +368 -0
- pyarchinit_mini/harris_matrix/pyarchinit_visualizer.py +581 -0
- pyarchinit_mini/i18n/__init__.py +15 -0
- pyarchinit_mini/i18n/flask_babel_config.py +94 -0
- pyarchinit_mini/i18n/locale_manager.py +142 -0
- pyarchinit_mini/mcp_server/__init__.py +22 -0
- pyarchinit_mini/mcp_server/__main__.py +45 -0
- pyarchinit_mini/mcp_server/blender_client.py +525 -0
- pyarchinit_mini/mcp_server/config.py +181 -0
- pyarchinit_mini/mcp_server/event_stream.py +282 -0
- pyarchinit_mini/mcp_server/graphml_parser.py +612 -0
- pyarchinit_mini/mcp_server/http_server.py +501 -0
- pyarchinit_mini/mcp_server/period_filter.py +362 -0
- pyarchinit_mini/mcp_server/prompts/__init__.py +18 -0
- pyarchinit_mini/mcp_server/prompts/base_prompt.py +23 -0
- pyarchinit_mini/mcp_server/prompts/period_visualization_prompt.py +25 -0
- pyarchinit_mini/mcp_server/prompts/stratigraphic_model_prompt.py +25 -0
- pyarchinit_mini/mcp_server/prompts/us_description_prompt.py +25 -0
- pyarchinit_mini/mcp_server/proxy_generator.py +470 -0
- pyarchinit_mini/mcp_server/resources/__init__.py +24 -0
- pyarchinit_mini/mcp_server/resources/base_resource.py +79 -0
- pyarchinit_mini/mcp_server/resources/graphml_resource.py +382 -0
- pyarchinit_mini/mcp_server/resources/periods_resource.py +52 -0
- pyarchinit_mini/mcp_server/resources/relationships_resource.py +52 -0
- pyarchinit_mini/mcp_server/resources/sites_resource.py +52 -0
- pyarchinit_mini/mcp_server/resources/us_resource.py +52 -0
- pyarchinit_mini/mcp_server/server.py +564 -0
- pyarchinit_mini/mcp_server/tools/__init__.py +24 -0
- pyarchinit_mini/mcp_server/tools/base_tool.py +119 -0
- pyarchinit_mini/mcp_server/tools/batch_insert_tool.py +393 -0
- pyarchinit_mini/mcp_server/tools/build_3d_tool.py +524 -0
- pyarchinit_mini/mcp_server/tools/chatgpt_fetch_tool.py +183 -0
- pyarchinit_mini/mcp_server/tools/chatgpt_search_tool.py +130 -0
- pyarchinit_mini/mcp_server/tools/configure_em_nodes_tool.py +427 -0
- pyarchinit_mini/mcp_server/tools/create_database_tool.py +118 -0
- pyarchinit_mini/mcp_server/tools/create_harris_matrix_tool.py +421 -0
- pyarchinit_mini/mcp_server/tools/data_import_parser_tool.py +695 -0
- pyarchinit_mini/mcp_server/tools/data_management_tool.py +262 -0
- pyarchinit_mini/mcp_server/tools/database_manager_tool.py +200 -0
- pyarchinit_mini/mcp_server/tools/delete_data_tool.py +288 -0
- pyarchinit_mini/mcp_server/tools/export_harris_matrix_graphml_tool.py +184 -0
- pyarchinit_mini/mcp_server/tools/export_tool.py +32 -0
- pyarchinit_mini/mcp_server/tools/filter_tool.py +32 -0
- pyarchinit_mini/mcp_server/tools/generate_report_tool.py +679 -0
- pyarchinit_mini/mcp_server/tools/get_schema_tool.py +224 -0
- pyarchinit_mini/mcp_server/tools/import_excel_tool.py +270 -0
- pyarchinit_mini/mcp_server/tools/insert_data_tool.py +390 -0
- pyarchinit_mini/mcp_server/tools/manage_services_tool.py +507 -0
- pyarchinit_mini/mcp_server/tools/material_tool.py +32 -0
- pyarchinit_mini/mcp_server/tools/media_management_tool.py +494 -0
- pyarchinit_mini/mcp_server/tools/position_tool.py +32 -0
- pyarchinit_mini/mcp_server/tools/pyarchinit_sync_tool.py +172 -0
- pyarchinit_mini/mcp_server/tools/resolve_conflicts_tool.py +377 -0
- pyarchinit_mini/mcp_server/tools/service_management_tool.py +104 -0
- pyarchinit_mini/mcp_server/tools/thesaurus_management_tool.py +420 -0
- pyarchinit_mini/mcp_server/tools/update_data_tool.py +360 -0
- pyarchinit_mini/mcp_server/tools/upload_file_tool.py +112 -0
- pyarchinit_mini/mcp_server/tools/validate_relationship_format_tool.py +327 -0
- pyarchinit_mini/mcp_server/tools/validate_relationship_integrity_tool.py +532 -0
- pyarchinit_mini/mcp_server/tools/validate_stratigraphic_relationships_tool.py +261 -0
- pyarchinit_mini/mcp_server/tools/validate_stratigraphy_tool.py +363 -0
- pyarchinit_mini/media_manager/__init__.py +9 -0
- pyarchinit_mini/media_manager/media_handler.py +322 -0
- pyarchinit_mini/models/__init__.py +35 -0
- pyarchinit_mini/models/base.py +32 -0
- pyarchinit_mini/models/datazione.py +68 -0
- pyarchinit_mini/models/extended_matrix.py +44 -0
- pyarchinit_mini/models/harris_matrix.py +117 -0
- pyarchinit_mini/models/inventario_materiali.py +238 -0
- pyarchinit_mini/models/media.py +109 -0
- pyarchinit_mini/models/site.py +96 -0
- pyarchinit_mini/models/thesaurus.py +179 -0
- pyarchinit_mini/models/us.py +291 -0
- pyarchinit_mini/models/user.py +78 -0
- pyarchinit_mini/pdf_export/__init__.py +9 -0
- pyarchinit_mini/pdf_export/pdf_generator.py +1048 -0
- pyarchinit_mini/pdf_export/pdf_generator_backup.py +1013 -0
- pyarchinit_mini/pdf_export/pyarchinit_finds_template.py +404 -0
- pyarchinit_mini/pdf_export/pyarchinit_inventory_template.py +353 -0
- pyarchinit_mini/pdf_export/usm_implementation.py +465 -0
- pyarchinit_mini/s3d_integration/__init__.py +9 -0
- pyarchinit_mini/s3d_integration/model_manager.py +234 -0
- pyarchinit_mini/s3d_integration/s3d_converter.py +848 -0
- pyarchinit_mini/scripts/__init__.py +3 -0
- pyarchinit_mini/scripts/auto_translate.py +679 -0
- pyarchinit_mini/scripts/configure_claude_desktop.py +277 -0
- pyarchinit_mini/scripts/create_admin_user.py +152 -0
- pyarchinit_mini/scripts/create_correct_stratigraphy_sample.py +373 -0
- pyarchinit_mini/scripts/create_italian_sample_database.py +302 -0
- pyarchinit_mini/scripts/create_sample_for_webapp.py +463 -0
- pyarchinit_mini/scripts/create_sample_with_50_us.py +353 -0
- pyarchinit_mini/scripts/generate_test_3d_model.py +323 -0
- pyarchinit_mini/scripts/load_italian_as_main.py +39 -0
- pyarchinit_mini/scripts/load_sample_as_main.py +73 -0
- pyarchinit_mini/scripts/migrate_relationships.py +165 -0
- pyarchinit_mini/scripts/populate_sample_data.py +498 -0
- pyarchinit_mini/scripts/populate_simple_data.py +213 -0
- pyarchinit_mini/scripts/setup_auth.py +112 -0
- pyarchinit_mini/scripts/setup_user_env.py +316 -0
- pyarchinit_mini/scripts/test_cascade_delete.py +91 -0
- pyarchinit_mini/scripts/test_relationship_fix.py +128 -0
- pyarchinit_mini/scripts/update_sample_relationships.py +136 -0
- pyarchinit_mini/scripts/update_urls_and_versions.py +312 -0
- pyarchinit_mini/scripts/verify_docs.py +312 -0
- pyarchinit_mini/services/__init__.py +19 -0
- pyarchinit_mini/services/analytics_service.py +242 -0
- pyarchinit_mini/services/command_parser.py +159 -0
- pyarchinit_mini/services/datazione_service.py +244 -0
- pyarchinit_mini/services/export_import_service.py +430 -0
- pyarchinit_mini/services/extended_matrix_excel_parser.py +708 -0
- pyarchinit_mini/services/import_export_service.py +2381 -0
- pyarchinit_mini/services/inventario_service.py +347 -0
- pyarchinit_mini/services/mcp_executor.py +206 -0
- pyarchinit_mini/services/media_service.py +458 -0
- pyarchinit_mini/services/periodizzazione_service.py +417 -0
- pyarchinit_mini/services/relationship_sync_service.py +400 -0
- pyarchinit_mini/services/site_service.py +328 -0
- pyarchinit_mini/services/thesaurus_service.py +358 -0
- pyarchinit_mini/services/us_service.py +446 -0
- pyarchinit_mini/services/user_service.py +293 -0
- pyarchinit_mini/translations/en/LC_MESSAGES/messages.mo +0 -0
- pyarchinit_mini/translations/en/LC_MESSAGES/messages.po +5110 -0
- pyarchinit_mini/translations/it/LC_MESSAGES/messages.mo +0 -0
- pyarchinit_mini/translations/it/LC_MESSAGES/messages.po +4798 -0
- pyarchinit_mini/translations/messages.pot +0 -0
- pyarchinit_mini/utils/__init__.py +27 -0
- pyarchinit_mini/utils/auth.py +143 -0
- pyarchinit_mini/utils/exceptions.py +38 -0
- pyarchinit_mini/utils/relationship_validator.py +388 -0
- pyarchinit_mini/utils/stratigraphic_validator.py +613 -0
- pyarchinit_mini/utils/validators.py +230 -0
- pyarchinit_mini/web_interface/app.py +4152 -0
- pyarchinit_mini/web_interface/auth_routes.py +263 -0
- pyarchinit_mini/web_interface/em_node_config_routes.py +280 -0
- pyarchinit_mini/web_interface/excel_import_routes.py +336 -0
- pyarchinit_mini/web_interface/harris_creator_routes.py +568 -0
- pyarchinit_mini/web_interface/pyarchinit_import_export_routes.py +888 -0
- pyarchinit_mini/web_interface/s3d_routes.py +361 -0
- pyarchinit_mini/web_interface/socketio_events.py +537 -0
- pyarchinit_mini/web_interface/static/css/style.css +4 -0
- pyarchinit_mini/web_interface/static/images/favicon.ico +0 -0
- pyarchinit_mini/web_interface/static/images/logo.png +0 -0
- pyarchinit_mini/web_interface/static/images/pyarchinit-mini-logo.png +0 -0
- pyarchinit_mini/web_interface/static/js/OrbitControls.js +1045 -0
- pyarchinit_mini/web_interface/static/js/harris_creator_editor.js +989 -0
- pyarchinit_mini/web_interface/static/js/stratigraphic_layout.js +782 -0
- pyarchinit_mini/web_interface/static/js/three-d-viewer.js +670 -0
- pyarchinit_mini/web_interface/static/js/three.min.js +6 -0
- pyarchinit_mini/web_interface/static/uploads/3d_models/Sito Archeologico di Esempio/site/stratigraphy_test.bin +0 -0
- pyarchinit_mini/web_interface/static/uploads/3d_models/Sito Archeologico di Esempio/site/stratigraphy_test.gltf +92 -0
- pyarchinit_mini/web_interface/static/uploads/3d_models/Sito Archeologico di Esempio/site/stratigraphy_test.mtl +71 -0
- pyarchinit_mini/web_interface/static/uploads/3d_models/Sito Archeologico di Esempio/site/stratigraphy_test.obj +244 -0
- pyarchinit_mini/web_interface/templates/3d_builder/index.html +2092 -0
- pyarchinit_mini/web_interface/templates/3d_viewer/viewer.html +259 -0
- pyarchinit_mini/web_interface/templates/admin/database.html +1140 -0
- pyarchinit_mini/web_interface/templates/admin/database_connect.html +188 -0
- pyarchinit_mini/web_interface/templates/admin/database_info.html +171 -0
- pyarchinit_mini/web_interface/templates/admin/database_upload.html +112 -0
- pyarchinit_mini/web_interface/templates/analytics/dashboard.html +414 -0
- pyarchinit_mini/web_interface/templates/auth/login.html +52 -0
- pyarchinit_mini/web_interface/templates/auth/users.html +217 -0
- pyarchinit_mini/web_interface/templates/base.html +765 -0
- pyarchinit_mini/web_interface/templates/blender_viewer.html +1285 -0
- pyarchinit_mini/web_interface/templates/components/language_switcher.html +47 -0
- pyarchinit_mini/web_interface/templates/dashboard.html +226 -0
- pyarchinit_mini/web_interface/templates/datazioni/list.html +62 -0
- pyarchinit_mini/web_interface/templates/em_node_config/index.html +430 -0
- pyarchinit_mini/web_interface/templates/excel_import/index.html +391 -0
- pyarchinit_mini/web_interface/templates/export/export_import.html +240 -0
- pyarchinit_mini/web_interface/templates/harris_creator/editor.html +373 -0
- pyarchinit_mini/web_interface/templates/harris_creator/index.html +196 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/graphml_export.html +300 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/large_graph_message.html +108 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/stratigraph_viewer.html +474 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/view.html +97 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/view_graphviz.html +202 -0
- pyarchinit_mini/web_interface/templates/harris_matrix/viewer_3d_integrated.html +1288 -0
- pyarchinit_mini/web_interface/templates/inventario/form.html +605 -0
- pyarchinit_mini/web_interface/templates/inventario/list.html +109 -0
- pyarchinit_mini/web_interface/templates/media/list.html +293 -0
- pyarchinit_mini/web_interface/templates/media/upload.html +125 -0
- pyarchinit_mini/web_interface/templates/periodizzazione/form.html +81 -0
- pyarchinit_mini/web_interface/templates/periodizzazione/list.html +102 -0
- pyarchinit_mini/web_interface/templates/periodizzazione/periods.html +107 -0
- pyarchinit_mini/web_interface/templates/pyarchinit_import_export/index.html +928 -0
- pyarchinit_mini/web_interface/templates/sites/detail.html +128 -0
- pyarchinit_mini/web_interface/templates/sites/form.html +315 -0
- pyarchinit_mini/web_interface/templates/sites/list.html +273 -0
- pyarchinit_mini/web_interface/templates/thesaurus/list.html +290 -0
- pyarchinit_mini/web_interface/templates/us/form.html +788 -0
- pyarchinit_mini/web_interface/templates/us/list.html +165 -0
- pyarchinit_mini/web_interface/templates/validation/report.html +253 -0
- pyarchinit_mini/web_interface/test_prova_extended_matrix.graphml +177 -0
- pyarchinit_mini/web_interface/three_d_builder_routes.py +1554 -0
- pyarchinit_mini/web_interface/uploads/graphml/Sito Archeologico di Esempio_stratigraphy.graphml +1792 -0
- pyarchinit_mini/web_interface/uploads/graphml/Sito Archeologico di Esempio_stratigraphy.json +2115 -0
- pyarchinit_mini/web_interface/web_interface/static/uploads/graphml/Scavo archeologico_heriverse.json +2132 -0
- pyarchinit_mini/web_interface/web_interface/static/uploads/graphml/Scavo archeologico_stratigraphy.graphml +2001 -0
- pyarchinit_mini/web_interface/web_interface/static/uploads/graphml/Scavo archeologico_stratigraphy.json +1782 -0
- pyarchinit_mini/web_interface/web_interface/static/uploads/graphml/Sito Archeologico di Esempio_stratigraphy.json +1457 -0
- pyarchinit_mini-1.9.28.dist-info/METADATA +2141 -0
- pyarchinit_mini-1.9.28.dist-info/RECORD +281 -0
- pyarchinit_mini-1.9.28.dist-info/WHEEL +5 -0
- pyarchinit_mini-1.9.28.dist-info/entry_points.txt +18 -0
- pyarchinit_mini-1.9.28.dist-info/top_level.txt +2 -0
- tests/__init__.py +1 -0
- tests/conftest.py +88 -0
- tests/unit/test_site_service.py +106 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Inventario Materiali API endpoints
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
7
|
+
|
|
8
|
+
from .schemas import InventarioCreate, InventarioUpdate, InventarioResponse, PaginatedResponse
|
|
9
|
+
from .dependencies import get_inventario_service
|
|
10
|
+
from ..services.inventario_service import InventarioService
|
|
11
|
+
from ..utils.exceptions import ValidationError, RecordNotFoundError
|
|
12
|
+
|
|
13
|
+
router = APIRouter()
|
|
14
|
+
|
|
15
|
+
@router.get("/", response_model=PaginatedResponse)
|
|
16
|
+
async def get_inventario_list(
|
|
17
|
+
page: int = Query(1, ge=1),
|
|
18
|
+
size: int = Query(10, ge=1, le=100),
|
|
19
|
+
sito: Optional[str] = Query(None, description="Filter by site"),
|
|
20
|
+
tipo_reperto: Optional[str] = Query(None, description="Filter by find type"),
|
|
21
|
+
inventario_service: InventarioService = Depends(get_inventario_service)
|
|
22
|
+
):
|
|
23
|
+
"""Get paginated list of inventory items"""
|
|
24
|
+
try:
|
|
25
|
+
filters = {}
|
|
26
|
+
if sito:
|
|
27
|
+
filters['sito'] = sito
|
|
28
|
+
if tipo_reperto:
|
|
29
|
+
filters['tipo_reperto'] = tipo_reperto
|
|
30
|
+
|
|
31
|
+
items = inventario_service.get_all_inventario(page=page, size=size, filters=filters)
|
|
32
|
+
total = inventario_service.count_inventario(filters=filters)
|
|
33
|
+
|
|
34
|
+
return PaginatedResponse(
|
|
35
|
+
items=[InventarioResponse.from_orm(item) for item in items],
|
|
36
|
+
total=total,
|
|
37
|
+
page=page,
|
|
38
|
+
size=size,
|
|
39
|
+
pages=(total + size - 1) // size
|
|
40
|
+
)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
43
|
+
|
|
44
|
+
@router.get("/{item_id}", response_model=InventarioResponse)
|
|
45
|
+
async def get_inventario_item(
|
|
46
|
+
item_id: int,
|
|
47
|
+
inventario_service: InventarioService = Depends(get_inventario_service)
|
|
48
|
+
):
|
|
49
|
+
"""Get inventory item by ID"""
|
|
50
|
+
try:
|
|
51
|
+
item = inventario_service.get_inventario_by_id(item_id)
|
|
52
|
+
if not item:
|
|
53
|
+
raise HTTPException(status_code=404, detail="Inventory item not found")
|
|
54
|
+
return InventarioResponse.from_orm(item)
|
|
55
|
+
except RecordNotFoundError:
|
|
56
|
+
raise HTTPException(status_code=404, detail="Inventory item not found")
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
59
|
+
|
|
60
|
+
@router.post("/", response_model=InventarioResponse, status_code=201)
|
|
61
|
+
async def create_inventario_item(
|
|
62
|
+
item_data: InventarioCreate,
|
|
63
|
+
inventario_service: InventarioService = Depends(get_inventario_service)
|
|
64
|
+
):
|
|
65
|
+
"""Create a new inventory item"""
|
|
66
|
+
try:
|
|
67
|
+
item = inventario_service.create_inventario(item_data.dict())
|
|
68
|
+
return InventarioResponse.from_orm(item)
|
|
69
|
+
except ValidationError as e:
|
|
70
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
71
|
+
except Exception as e:
|
|
72
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
73
|
+
|
|
74
|
+
@router.put("/{item_id}", response_model=InventarioResponse)
|
|
75
|
+
async def update_inventario_item(
|
|
76
|
+
item_id: int,
|
|
77
|
+
item_data: InventarioUpdate,
|
|
78
|
+
inventario_service: InventarioService = Depends(get_inventario_service)
|
|
79
|
+
):
|
|
80
|
+
"""Update an existing inventory item"""
|
|
81
|
+
try:
|
|
82
|
+
update_data = {k: v for k, v in item_data.dict().items() if v is not None}
|
|
83
|
+
item = inventario_service.update_inventario(item_id, update_data)
|
|
84
|
+
return InventarioResponse.from_orm(item)
|
|
85
|
+
except RecordNotFoundError:
|
|
86
|
+
raise HTTPException(status_code=404, detail="Inventory item not found")
|
|
87
|
+
except ValidationError as e:
|
|
88
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
89
|
+
except Exception as e:
|
|
90
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
91
|
+
|
|
92
|
+
@router.delete("/{item_id}")
|
|
93
|
+
async def delete_inventario_item(
|
|
94
|
+
item_id: int,
|
|
95
|
+
inventario_service: InventarioService = Depends(get_inventario_service)
|
|
96
|
+
):
|
|
97
|
+
"""Delete an inventory item"""
|
|
98
|
+
try:
|
|
99
|
+
success = inventario_service.delete_inventario(item_id)
|
|
100
|
+
if success:
|
|
101
|
+
return {"message": "Inventory item deleted successfully"}
|
|
102
|
+
else:
|
|
103
|
+
raise HTTPException(status_code=404, detail="Inventory item not found")
|
|
104
|
+
except RecordNotFoundError:
|
|
105
|
+
raise HTTPException(status_code=404, detail="Inventory item not found")
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic schemas for API request/response validation
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Optional, List
|
|
7
|
+
from pydantic import BaseModel, Field, validator
|
|
8
|
+
|
|
9
|
+
# Base schemas
|
|
10
|
+
|
|
11
|
+
class BaseSchema(BaseModel):
|
|
12
|
+
"""Base schema with common fields"""
|
|
13
|
+
created_at: Optional[datetime] = None
|
|
14
|
+
updated_at: Optional[datetime] = None
|
|
15
|
+
|
|
16
|
+
class Config:
|
|
17
|
+
from_attributes = True
|
|
18
|
+
|
|
19
|
+
# Site schemas
|
|
20
|
+
|
|
21
|
+
class SiteBase(BaseModel):
|
|
22
|
+
"""Base site schema"""
|
|
23
|
+
sito: str = Field(..., min_length=1, max_length=350, description="Site name")
|
|
24
|
+
nazione: Optional[str] = Field(None, max_length=250, description="Country")
|
|
25
|
+
regione: Optional[str] = Field(None, max_length=250, description="Region")
|
|
26
|
+
comune: Optional[str] = Field(None, max_length=250, description="Municipality")
|
|
27
|
+
provincia: Optional[str] = Field(None, max_length=10, description="Province")
|
|
28
|
+
definizione_sito: Optional[str] = Field(None, max_length=250, description="Site definition")
|
|
29
|
+
descrizione: Optional[str] = Field(None, description="Description")
|
|
30
|
+
sito_path: Optional[str] = Field(None, max_length=500, description="Site path")
|
|
31
|
+
find_check: Optional[bool] = Field(False, description="Find check flag")
|
|
32
|
+
|
|
33
|
+
class SiteCreate(SiteBase):
|
|
34
|
+
"""Schema for creating a site"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
class SiteUpdate(BaseModel):
|
|
38
|
+
"""Schema for updating a site"""
|
|
39
|
+
sito: Optional[str] = Field(None, min_length=1, max_length=350)
|
|
40
|
+
nazione: Optional[str] = Field(None, max_length=250)
|
|
41
|
+
regione: Optional[str] = Field(None, max_length=250)
|
|
42
|
+
comune: Optional[str] = Field(None, max_length=250)
|
|
43
|
+
provincia: Optional[str] = Field(None, max_length=10)
|
|
44
|
+
definizione_sito: Optional[str] = Field(None, max_length=250)
|
|
45
|
+
descrizione: Optional[str] = None
|
|
46
|
+
sito_path: Optional[str] = Field(None, max_length=500)
|
|
47
|
+
find_check: Optional[bool] = None
|
|
48
|
+
|
|
49
|
+
class SiteResponse(SiteBase, BaseSchema):
|
|
50
|
+
"""Schema for site response"""
|
|
51
|
+
id_sito: int = Field(..., description="Site ID")
|
|
52
|
+
|
|
53
|
+
# US (Stratigraphic Unit) schemas
|
|
54
|
+
|
|
55
|
+
class USBase(BaseModel):
|
|
56
|
+
"""Base US schema"""
|
|
57
|
+
sito: str = Field(..., max_length=350, description="Site name")
|
|
58
|
+
area: Optional[str] = Field(None, max_length=20, description="Area")
|
|
59
|
+
us: int = Field(..., gt=0, description="US number")
|
|
60
|
+
d_stratigrafica: Optional[str] = Field(None, max_length=350, description="Stratigraphic description")
|
|
61
|
+
d_interpretativa: Optional[str] = Field(None, max_length=350, description="Interpretative description")
|
|
62
|
+
descrizione: Optional[str] = Field(None, description="Description")
|
|
63
|
+
interpretazione: Optional[str] = Field(None, description="Interpretation")
|
|
64
|
+
periodo_iniziale: Optional[str] = Field(None, max_length=300, description="Initial period")
|
|
65
|
+
fase_iniziale: Optional[str] = Field(None, max_length=300, description="Initial phase")
|
|
66
|
+
periodo_finale: Optional[str] = Field(None, max_length=300, description="Final period")
|
|
67
|
+
fase_finale: Optional[str] = Field(None, max_length=300, description="Final phase")
|
|
68
|
+
scavato: Optional[str] = Field(None, max_length=20, description="Excavated")
|
|
69
|
+
attivita: Optional[str] = Field(None, max_length=30, description="Activity")
|
|
70
|
+
anno_scavo: Optional[int] = Field(None, ge=1800, le=2100, description="Excavation year")
|
|
71
|
+
metodo_di_scavo: Optional[str] = Field(None, max_length=20, description="Excavation method")
|
|
72
|
+
schedatore: Optional[str] = Field(None, max_length=100, description="Recorder")
|
|
73
|
+
formazione: Optional[str] = Field(None, max_length=20, description="Formation")
|
|
74
|
+
stato_di_conservazione: Optional[str] = Field(None, max_length=20, description="Conservation state")
|
|
75
|
+
colore: Optional[str] = Field(None, max_length=20, description="Color")
|
|
76
|
+
consistenza: Optional[str] = Field(None, max_length=20, description="Consistency")
|
|
77
|
+
struttura: Optional[str] = Field(None, max_length=30, description="Structure")
|
|
78
|
+
|
|
79
|
+
# Measurements
|
|
80
|
+
quota_relativa: Optional[float] = Field(None, ge=0, description="Relative elevation")
|
|
81
|
+
quota_abs: Optional[float] = Field(None, ge=0, description="Absolute elevation")
|
|
82
|
+
lunghezza_max: Optional[float] = Field(None, ge=0, description="Maximum length")
|
|
83
|
+
altezza_max: Optional[float] = Field(None, ge=0, description="Maximum height")
|
|
84
|
+
altezza_min: Optional[float] = Field(None, ge=0, description="Minimum height")
|
|
85
|
+
profondita_max: Optional[float] = Field(None, ge=0, description="Maximum depth")
|
|
86
|
+
profondita_min: Optional[float] = Field(None, ge=0, description="Minimum depth")
|
|
87
|
+
larghezza_media: Optional[float] = Field(None, ge=0, description="Average width")
|
|
88
|
+
|
|
89
|
+
# Additional fields
|
|
90
|
+
osservazioni: Optional[str] = Field(None, description="Observations")
|
|
91
|
+
datazione: Optional[str] = Field(None, max_length=100, description="Dating")
|
|
92
|
+
direttore_us: Optional[str] = Field(None, max_length=100, description="US director")
|
|
93
|
+
responsabile_us: Optional[str] = Field(None, max_length=100, description="US responsible")
|
|
94
|
+
|
|
95
|
+
class USCreate(USBase):
|
|
96
|
+
"""Schema for creating a US"""
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
class USUpdate(BaseModel):
|
|
100
|
+
"""Schema for updating a US"""
|
|
101
|
+
sito: Optional[str] = Field(None, max_length=350)
|
|
102
|
+
area: Optional[str] = Field(None, max_length=20)
|
|
103
|
+
us: Optional[int] = Field(None, gt=0)
|
|
104
|
+
d_stratigrafica: Optional[str] = Field(None, max_length=350)
|
|
105
|
+
d_interpretativa: Optional[str] = Field(None, max_length=350)
|
|
106
|
+
descrizione: Optional[str] = None
|
|
107
|
+
interpretazione: Optional[str] = None
|
|
108
|
+
anno_scavo: Optional[int] = Field(None, ge=1800, le=2100)
|
|
109
|
+
schedatore: Optional[str] = Field(None, max_length=100)
|
|
110
|
+
# ... other optional fields
|
|
111
|
+
|
|
112
|
+
class USResponse(USBase, BaseSchema):
|
|
113
|
+
"""Schema for US response"""
|
|
114
|
+
id_us: int = Field(..., description="US ID")
|
|
115
|
+
|
|
116
|
+
# Inventario Materiali schemas
|
|
117
|
+
|
|
118
|
+
class InventarioBase(BaseModel):
|
|
119
|
+
"""Base inventory schema"""
|
|
120
|
+
sito: str = Field(..., max_length=350, description="Site name")
|
|
121
|
+
numero_inventario: int = Field(..., gt=0, description="Inventory number")
|
|
122
|
+
tipo_reperto: Optional[str] = Field(None, max_length=20, description="Find type")
|
|
123
|
+
criterio_schedatura: Optional[str] = Field(None, max_length=20, description="Recording criteria")
|
|
124
|
+
definizione: Optional[str] = Field(None, max_length=20, description="Definition")
|
|
125
|
+
descrizione: Optional[str] = Field(None, description="Description")
|
|
126
|
+
area: Optional[str] = Field(None, max_length=20, description="Area")
|
|
127
|
+
us: Optional[int] = Field(None, gt=0, description="US number")
|
|
128
|
+
lavato: Optional[str] = Field(None, max_length=5, description="Washed")
|
|
129
|
+
nr_cassa: Optional[str] = Field(None, max_length=20, description="Box number")
|
|
130
|
+
luogo_conservazione: Optional[str] = Field(None, max_length=350, description="Conservation location")
|
|
131
|
+
stato_conservazione: Optional[str] = Field(None, max_length=200, description="Conservation state")
|
|
132
|
+
datazione_reperto: Optional[str] = Field(None, max_length=100, description="Find dating")
|
|
133
|
+
|
|
134
|
+
# Technical characteristics
|
|
135
|
+
forme_minime: Optional[int] = Field(None, ge=0, description="Minimum forms")
|
|
136
|
+
forme_massime: Optional[int] = Field(None, ge=0, description="Maximum forms")
|
|
137
|
+
totale_frammenti: Optional[int] = Field(None, ge=0, description="Total fragments")
|
|
138
|
+
peso: Optional[float] = Field(None, ge=0, description="Weight")
|
|
139
|
+
diametro_orlo: Optional[float] = Field(None, ge=0, description="Rim diameter")
|
|
140
|
+
eve_orlo: Optional[float] = Field(None, ge=0, le=100, description="Rim EVE")
|
|
141
|
+
|
|
142
|
+
# Classification
|
|
143
|
+
corpo_ceramico: Optional[str] = Field(None, max_length=20, description="Ceramic body")
|
|
144
|
+
rivestimento: Optional[str] = Field(None, max_length=20, description="Surface treatment")
|
|
145
|
+
tipo: Optional[str] = Field(None, max_length=300, description="Type")
|
|
146
|
+
repertato: Optional[str] = Field(None, max_length=2, description="Catalogued")
|
|
147
|
+
diagnostico: Optional[str] = Field(None, max_length=2, description="Diagnostic")
|
|
148
|
+
|
|
149
|
+
@validator('lavato', 'repertato', 'diagnostico')
|
|
150
|
+
def validate_yes_no_fields(cls, v):
|
|
151
|
+
if v is not None and v.upper() not in ['SI', 'NO', 'S', 'N']:
|
|
152
|
+
raise ValueError('Must be SI/NO or S/N')
|
|
153
|
+
return v
|
|
154
|
+
|
|
155
|
+
class InventarioCreate(InventarioBase):
|
|
156
|
+
"""Schema for creating inventory item"""
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
class InventarioUpdate(BaseModel):
|
|
160
|
+
"""Schema for updating inventory item"""
|
|
161
|
+
sito: Optional[str] = Field(None, max_length=350)
|
|
162
|
+
numero_inventario: Optional[int] = Field(None, gt=0)
|
|
163
|
+
tipo_reperto: Optional[str] = Field(None, max_length=20)
|
|
164
|
+
# ... other optional fields
|
|
165
|
+
|
|
166
|
+
class InventarioResponse(InventarioBase, BaseSchema):
|
|
167
|
+
"""Schema for inventory response"""
|
|
168
|
+
id_invmat: int = Field(..., description="Inventory ID")
|
|
169
|
+
|
|
170
|
+
# Pagination schemas
|
|
171
|
+
|
|
172
|
+
class PaginationParams(BaseModel):
|
|
173
|
+
"""Pagination parameters"""
|
|
174
|
+
page: int = Field(1, ge=1, description="Page number")
|
|
175
|
+
size: int = Field(10, ge=1, le=100, description="Page size")
|
|
176
|
+
|
|
177
|
+
class PaginatedResponse(BaseModel):
|
|
178
|
+
"""Paginated response wrapper"""
|
|
179
|
+
items: List[BaseModel]
|
|
180
|
+
total: int = Field(..., description="Total number of items")
|
|
181
|
+
page: int = Field(..., description="Current page")
|
|
182
|
+
size: int = Field(..., description="Page size")
|
|
183
|
+
pages: int = Field(..., description="Total number of pages")
|
|
184
|
+
|
|
185
|
+
class Config:
|
|
186
|
+
from_attributes = True
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Site API endpoints
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
7
|
+
from fastapi.responses import JSONResponse
|
|
8
|
+
|
|
9
|
+
from .schemas import SiteCreate, SiteUpdate, SiteResponse, PaginatedResponse
|
|
10
|
+
from .dependencies import get_site_service
|
|
11
|
+
from ..services.site_service import SiteService
|
|
12
|
+
from ..utils.exceptions import ValidationError, RecordNotFoundError, DuplicateRecordError
|
|
13
|
+
|
|
14
|
+
router = APIRouter()
|
|
15
|
+
|
|
16
|
+
@router.get("/", response_model=PaginatedResponse)
|
|
17
|
+
async def get_sites(
|
|
18
|
+
page: int = Query(1, ge=1, description="Page number"),
|
|
19
|
+
size: int = Query(10, ge=1, le=100, description="Page size"),
|
|
20
|
+
search: Optional[str] = Query(None, description="Search term"),
|
|
21
|
+
nazione: Optional[str] = Query(None, description="Filter by country"),
|
|
22
|
+
regione: Optional[str] = Query(None, description="Filter by region"),
|
|
23
|
+
comune: Optional[str] = Query(None, description="Filter by municipality"),
|
|
24
|
+
site_service: SiteService = Depends(get_site_service)
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Get paginated list of sites with optional filtering and search
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
# Build filters
|
|
31
|
+
filters = {}
|
|
32
|
+
if nazione:
|
|
33
|
+
filters['nazione'] = nazione
|
|
34
|
+
if regione:
|
|
35
|
+
filters['regione'] = regione
|
|
36
|
+
if comune:
|
|
37
|
+
filters['comune'] = comune
|
|
38
|
+
|
|
39
|
+
# Get sites
|
|
40
|
+
if search:
|
|
41
|
+
sites = site_service.search_sites(search, page=page, size=size, filters=filters)
|
|
42
|
+
else:
|
|
43
|
+
sites = site_service.get_all_sites(page=page, size=size, filters=filters)
|
|
44
|
+
|
|
45
|
+
# Get total count for pagination
|
|
46
|
+
total = site_service.count_sites(filters=filters)
|
|
47
|
+
|
|
48
|
+
return PaginatedResponse(
|
|
49
|
+
items=[SiteResponse.from_orm(site) for site in sites],
|
|
50
|
+
total=total,
|
|
51
|
+
page=page,
|
|
52
|
+
size=size,
|
|
53
|
+
pages=(total + size - 1) // size
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
58
|
+
|
|
59
|
+
@router.get("/{site_id}", response_model=SiteResponse)
|
|
60
|
+
async def get_site(
|
|
61
|
+
site_id: int,
|
|
62
|
+
site_service: SiteService = Depends(get_site_service)
|
|
63
|
+
):
|
|
64
|
+
"""
|
|
65
|
+
Get site by ID
|
|
66
|
+
"""
|
|
67
|
+
try:
|
|
68
|
+
site = site_service.get_site_by_id(site_id)
|
|
69
|
+
if not site:
|
|
70
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
71
|
+
return SiteResponse.from_orm(site)
|
|
72
|
+
|
|
73
|
+
except RecordNotFoundError:
|
|
74
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
75
|
+
except Exception as e:
|
|
76
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
77
|
+
|
|
78
|
+
@router.get("/by-name/{site_name}", response_model=SiteResponse)
|
|
79
|
+
async def get_site_by_name(
|
|
80
|
+
site_name: str,
|
|
81
|
+
site_service: SiteService = Depends(get_site_service)
|
|
82
|
+
):
|
|
83
|
+
"""
|
|
84
|
+
Get site by name
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
site = site_service.get_site_by_name(site_name)
|
|
88
|
+
if not site:
|
|
89
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
90
|
+
return SiteResponse.from_orm(site)
|
|
91
|
+
|
|
92
|
+
except RecordNotFoundError:
|
|
93
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
96
|
+
|
|
97
|
+
@router.post("/", response_model=SiteResponse, status_code=201)
|
|
98
|
+
async def create_site(
|
|
99
|
+
site_data: SiteCreate,
|
|
100
|
+
site_service: SiteService = Depends(get_site_service)
|
|
101
|
+
):
|
|
102
|
+
"""
|
|
103
|
+
Create a new site
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
site = site_service.create_site(site_data.dict())
|
|
107
|
+
return SiteResponse.from_orm(site)
|
|
108
|
+
|
|
109
|
+
except ValidationError as e:
|
|
110
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
111
|
+
except DuplicateRecordError as e:
|
|
112
|
+
raise HTTPException(status_code=409, detail=str(e))
|
|
113
|
+
except Exception as e:
|
|
114
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
115
|
+
|
|
116
|
+
@router.put("/{site_id}", response_model=SiteResponse)
|
|
117
|
+
async def update_site(
|
|
118
|
+
site_id: int,
|
|
119
|
+
site_data: SiteUpdate,
|
|
120
|
+
site_service: SiteService = Depends(get_site_service)
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Update an existing site
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
# Only include non-None values in update
|
|
127
|
+
update_data = {k: v for k, v in site_data.dict().items() if v is not None}
|
|
128
|
+
site = site_service.update_site(site_id, update_data)
|
|
129
|
+
return SiteResponse.from_orm(site)
|
|
130
|
+
|
|
131
|
+
except RecordNotFoundError:
|
|
132
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
133
|
+
except ValidationError as e:
|
|
134
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
135
|
+
except DuplicateRecordError as e:
|
|
136
|
+
raise HTTPException(status_code=409, detail=str(e))
|
|
137
|
+
except Exception as e:
|
|
138
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
139
|
+
|
|
140
|
+
@router.delete("/{site_id}")
|
|
141
|
+
async def delete_site(
|
|
142
|
+
site_id: int,
|
|
143
|
+
site_service: SiteService = Depends(get_site_service)
|
|
144
|
+
):
|
|
145
|
+
"""
|
|
146
|
+
Delete a site
|
|
147
|
+
"""
|
|
148
|
+
try:
|
|
149
|
+
success = site_service.delete_site(site_id)
|
|
150
|
+
if success:
|
|
151
|
+
return JSONResponse(
|
|
152
|
+
status_code=200,
|
|
153
|
+
content={"message": "Site deleted successfully"}
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
157
|
+
|
|
158
|
+
except RecordNotFoundError:
|
|
159
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
162
|
+
|
|
163
|
+
@router.get("/{site_id}/stats")
|
|
164
|
+
async def get_site_stats(
|
|
165
|
+
site_id: int,
|
|
166
|
+
site_service: SiteService = Depends(get_site_service)
|
|
167
|
+
):
|
|
168
|
+
"""
|
|
169
|
+
Get statistics for a site (US count, inventory count, etc.)
|
|
170
|
+
"""
|
|
171
|
+
try:
|
|
172
|
+
stats = site_service.get_site_statistics(site_id)
|
|
173
|
+
return stats
|
|
174
|
+
|
|
175
|
+
except RecordNotFoundError:
|
|
176
|
+
raise HTTPException(status_code=404, detail="Site not found")
|
|
177
|
+
except Exception as e:
|
|
178
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
179
|
+
|
|
180
|
+
@router.get("/locations/countries")
|
|
181
|
+
async def get_countries(
|
|
182
|
+
site_service: SiteService = Depends(get_site_service)
|
|
183
|
+
):
|
|
184
|
+
"""
|
|
185
|
+
Get list of unique countries from sites
|
|
186
|
+
"""
|
|
187
|
+
try:
|
|
188
|
+
countries = site_service.get_unique_countries()
|
|
189
|
+
return {"countries": countries}
|
|
190
|
+
except Exception as e:
|
|
191
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
192
|
+
|
|
193
|
+
@router.get("/locations/regions")
|
|
194
|
+
async def get_regions(
|
|
195
|
+
nazione: Optional[str] = Query(None, description="Filter by country"),
|
|
196
|
+
site_service: SiteService = Depends(get_site_service)
|
|
197
|
+
):
|
|
198
|
+
"""
|
|
199
|
+
Get list of unique regions, optionally filtered by country
|
|
200
|
+
"""
|
|
201
|
+
try:
|
|
202
|
+
regions = site_service.get_unique_regions(nazione)
|
|
203
|
+
return {"regions": regions}
|
|
204
|
+
except Exception as e:
|
|
205
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
206
|
+
|
|
207
|
+
@router.get("/locations/municipalities")
|
|
208
|
+
async def get_municipalities(
|
|
209
|
+
nazione: Optional[str] = Query(None, description="Filter by country"),
|
|
210
|
+
regione: Optional[str] = Query(None, description="Filter by region"),
|
|
211
|
+
site_service: SiteService = Depends(get_site_service)
|
|
212
|
+
):
|
|
213
|
+
"""
|
|
214
|
+
Get list of unique municipalities, optionally filtered by country and region
|
|
215
|
+
"""
|
|
216
|
+
try:
|
|
217
|
+
municipalities = site_service.get_unique_municipalities(nazione, regione)
|
|
218
|
+
return {"municipalities": municipalities}
|
|
219
|
+
except Exception as e:
|
|
220
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
US (Stratigraphic Unit) API endpoints
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
7
|
+
|
|
8
|
+
from .schemas import USCreate, USUpdate, USResponse, PaginatedResponse
|
|
9
|
+
from .dependencies import get_us_service
|
|
10
|
+
from ..services.us_service import USService
|
|
11
|
+
from ..utils.exceptions import ValidationError, RecordNotFoundError
|
|
12
|
+
|
|
13
|
+
router = APIRouter()
|
|
14
|
+
|
|
15
|
+
@router.get("/", response_model=PaginatedResponse)
|
|
16
|
+
async def get_us_list(
|
|
17
|
+
page: int = Query(1, ge=1),
|
|
18
|
+
size: int = Query(10, ge=1, le=100),
|
|
19
|
+
sito: Optional[str] = Query(None, description="Filter by site"),
|
|
20
|
+
area: Optional[str] = Query(None, description="Filter by area"),
|
|
21
|
+
us_service: USService = Depends(get_us_service)
|
|
22
|
+
):
|
|
23
|
+
"""Get paginated list of stratigraphic units"""
|
|
24
|
+
try:
|
|
25
|
+
filters = {}
|
|
26
|
+
if sito:
|
|
27
|
+
filters['sito'] = sito
|
|
28
|
+
if area:
|
|
29
|
+
filters['area'] = area
|
|
30
|
+
|
|
31
|
+
us_list = us_service.get_all_us(page=page, size=size, filters=filters)
|
|
32
|
+
total = us_service.count_us(filters=filters)
|
|
33
|
+
|
|
34
|
+
return PaginatedResponse(
|
|
35
|
+
items=[USResponse.from_orm(us) for us in us_list],
|
|
36
|
+
total=total,
|
|
37
|
+
page=page,
|
|
38
|
+
size=size,
|
|
39
|
+
pages=(total + size - 1) // size
|
|
40
|
+
)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
43
|
+
|
|
44
|
+
@router.get("/{us_id}", response_model=USResponse)
|
|
45
|
+
async def get_us(
|
|
46
|
+
us_id: int,
|
|
47
|
+
us_service: USService = Depends(get_us_service)
|
|
48
|
+
):
|
|
49
|
+
"""Get US by ID"""
|
|
50
|
+
try:
|
|
51
|
+
us = us_service.get_us_by_id(us_id)
|
|
52
|
+
if not us:
|
|
53
|
+
raise HTTPException(status_code=404, detail="US not found")
|
|
54
|
+
return USResponse.from_orm(us)
|
|
55
|
+
except RecordNotFoundError:
|
|
56
|
+
raise HTTPException(status_code=404, detail="US not found")
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
59
|
+
|
|
60
|
+
@router.post("/", response_model=USResponse, status_code=201)
|
|
61
|
+
async def create_us(
|
|
62
|
+
us_data: USCreate,
|
|
63
|
+
us_service: USService = Depends(get_us_service)
|
|
64
|
+
):
|
|
65
|
+
"""Create a new stratigraphic unit"""
|
|
66
|
+
try:
|
|
67
|
+
us = us_service.create_us(us_data.dict())
|
|
68
|
+
return USResponse.from_orm(us)
|
|
69
|
+
except ValidationError as e:
|
|
70
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
71
|
+
except Exception as e:
|
|
72
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
73
|
+
|
|
74
|
+
@router.put("/{us_id}", response_model=USResponse)
|
|
75
|
+
async def update_us(
|
|
76
|
+
us_id: int,
|
|
77
|
+
us_data: USUpdate,
|
|
78
|
+
us_service: USService = Depends(get_us_service)
|
|
79
|
+
):
|
|
80
|
+
"""Update an existing stratigraphic unit"""
|
|
81
|
+
try:
|
|
82
|
+
update_data = {k: v for k, v in us_data.dict().items() if v is not None}
|
|
83
|
+
us = us_service.update_us(us_id, update_data)
|
|
84
|
+
return USResponse.from_orm(us)
|
|
85
|
+
except RecordNotFoundError:
|
|
86
|
+
raise HTTPException(status_code=404, detail="US not found")
|
|
87
|
+
except ValidationError as e:
|
|
88
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
89
|
+
except Exception as e:
|
|
90
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
91
|
+
|
|
92
|
+
@router.delete("/{us_id}")
|
|
93
|
+
async def delete_us(
|
|
94
|
+
us_id: int,
|
|
95
|
+
us_service: USService = Depends(get_us_service)
|
|
96
|
+
):
|
|
97
|
+
"""Delete a stratigraphic unit"""
|
|
98
|
+
try:
|
|
99
|
+
success = us_service.delete_us(us_id)
|
|
100
|
+
if success:
|
|
101
|
+
return {"message": "US deleted successfully"}
|
|
102
|
+
else:
|
|
103
|
+
raise HTTPException(status_code=404, detail="US not found")
|
|
104
|
+
except RecordNotFoundError:
|
|
105
|
+
raise HTTPException(status_code=404, detail="US not found")
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise HTTPException(status_code=500, detail=str(e))
|