netbox-pathways 0.2.0__tar.gz → 0.2.1__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.
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/PKG-INFO +8 -1
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/README.md +7 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/__init__.py +6 -2
- netbox_pathways-0.2.1/netbox_pathways/checks.py +86 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0004_circuit_geometry.py +5 -1
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/PKG-INFO +8 -1
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/SOURCES.txt +3 -1
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/pyproject.toml +2 -2
- netbox_pathways-0.2.1/tests/test_srid_checks.py +73 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/external_geo.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/geo.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/serializers.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/traversal.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/urls.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/api/views.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/choices.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/filterforms.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/filters.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/forms.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/geo.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/graph.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/graphql/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/graphql/filters.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/graphql/schema.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/graphql/types.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/_geodata_worker.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/generate_qgis_project.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/generate_sample_data.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/import_geodata.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0001_initial.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0002_replace_owner_with_tenant.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0003_structure_optional_site_dimensions.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0005_replace_unique_together_with_constraints.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0006_remove_cablesegment_sequence_enter_exit.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0007_cable_routing_redesign.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0008_conduitbank_pathway_subclass.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0009_remove_conduit_unique_position_per_bank_and_more.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0010_structure_status.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0011_rename_name_to_label.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0012_add_filter_field_indexes.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0013_plannedroute.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0014_plannedroute_parent_split.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0015_installer_and_commissioned_date.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0016_cablesegment_lashed_with.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/models.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/navigation.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/registry.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/route_engine.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/routing.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/search.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/signals.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/css/leaflet-theme.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/css/pathways-map.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/detail-map.min.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/detail-map.min.js.map +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/endpoint-markers.min.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/endpoint-markers.min.js.map +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/pathways-field.min.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/pathways-field.min.js.map +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/pathways-map.min.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/pathways-map.min.js.map +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/route-planner-map.min.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/dist/route-planner-map.min.js.map +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/qgis/pathways.qml +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/qgis/structures.qml +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/MarkerCluster.Default.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/MarkerCluster.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/geoman/leaflet-geoman.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/geoman/leaflet-geoman.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/images/layers-2x.png +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/images/layers.png +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/images/marker-icon-2x.png +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/images/marker-icon.png +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/images/marker-shadow.png +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/leaflet.css +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet/leaflet.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/static/netbox_pathways/vendor/leaflet.markercluster.js +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/tables.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/template_content.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/aerialspan.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/buttons/apply_route.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/buttons/replan_route.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/buttons/revert_split.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/buttons/split_route.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/buttons/view_in_map.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/cable_route_tab.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/cablesegment.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/conduit.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/conduitbank.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/conduitjunction.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/directburied.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/cable_add_segment_form.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/cable_route_finder_results.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/cable_routing_panel.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/cable_segment_table.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/connected_structures_panel.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/constraint_card.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/geo_map_panel.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/plannedroute_map_panel.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/inc/planner_results.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/innerduct.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/map.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/pathway.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/pathwaylocation.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/plannedroute.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/plannedroute_apply.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/plannedroute_split.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/pullsheet_detail.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/pullsheet_list.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/route_planner.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/sitegeometry.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/structure.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/widgets/map_widget.html +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/ui/__init__.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/ui/panels.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/urls.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/views.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/dependency_links.txt +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/requires.txt +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/top_level.txt +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/setup.cfg +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_adjacency.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_cable_segment.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_circuit_geometry.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_endpoint_validation.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_external_geo.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_field_additions.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_geo_api.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_graph.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_graphql.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_import_geodata.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_lashed_with.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_map_view.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_planned_route.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_registry.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_route_engine.py +0 -0
- {netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/tests/test_routing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-pathways
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: NetBox plugin for physical cable plant infrastructure documentation with GIS capabilities
|
|
5
5
|
Author-email: Jonathan Senecal <contact@jonathansenecal.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/jsenecal/netbox-pathways
|
|
@@ -179,6 +179,13 @@ Full documentation: **[jsenecal.github.io/netbox-pathways](https://jsenecal.gith
|
|
|
179
179
|
- [Architecture](https://jsenecal.github.io/netbox-pathways/developer/architecture/)
|
|
180
180
|
- [GeoJSON API reference](https://jsenecal.github.io/netbox-pathways/reference/geojson-api/)
|
|
181
181
|
|
|
182
|
+
## Related plugins
|
|
183
|
+
|
|
184
|
+
netbox-pathways is part of a three-plugin set that models the full optical transport stack:
|
|
185
|
+
|
|
186
|
+
- **[netbox-fms](https://github.com/jsenecal/netbox-fms)** -- Fiber Management System. Defines fiber cable construction (buffer tubes, ribbons, strands), plans splices in closures, and provisions end-to-end fiber circuits. Pathways tracks *where cables run*; FMS tracks *what is inside them and how strands are spliced*.
|
|
187
|
+
- **[netbox-wdm](https://github.com/jsenecal/netbox-wdm)** -- WDM (Wavelength Division Multiplexing) device management. Models ITU channel plans, ROADM mappings, and wavelength services that ride on top of the fiber circuits FMS provisions, over the cables routed through Pathways.
|
|
188
|
+
|
|
182
189
|
## Contributing
|
|
183
190
|
|
|
184
191
|
PRs welcome. Use conventional-commits PR titles (`feat:`, `fix:`, `chore:`, `docs:`, ...) -- release-drafter assembles release notes from them. Run `make setup` after cloning to install dev dependencies and the pre-commit hooks (including the AI-attribution-rejecting `commit-msg` hook).
|
|
@@ -149,6 +149,13 @@ Full documentation: **[jsenecal.github.io/netbox-pathways](https://jsenecal.gith
|
|
|
149
149
|
- [Architecture](https://jsenecal.github.io/netbox-pathways/developer/architecture/)
|
|
150
150
|
- [GeoJSON API reference](https://jsenecal.github.io/netbox-pathways/reference/geojson-api/)
|
|
151
151
|
|
|
152
|
+
## Related plugins
|
|
153
|
+
|
|
154
|
+
netbox-pathways is part of a three-plugin set that models the full optical transport stack:
|
|
155
|
+
|
|
156
|
+
- **[netbox-fms](https://github.com/jsenecal/netbox-fms)** -- Fiber Management System. Defines fiber cable construction (buffer tubes, ribbons, strands), plans splices in closures, and provisions end-to-end fiber circuits. Pathways tracks *where cables run*; FMS tracks *what is inside them and how strands are spliced*.
|
|
157
|
+
- **[netbox-wdm](https://github.com/jsenecal/netbox-wdm)** -- WDM (Wavelength Division Multiplexing) device management. Models ITU channel plans, ROADM mappings, and wavelength services that ride on top of the fiber circuits FMS provisions, over the cables routed through Pathways.
|
|
158
|
+
|
|
152
159
|
## Contributing
|
|
153
160
|
|
|
154
161
|
PRs welcome. Use conventional-commits PR titles (`feat:`, `fix:`, `chore:`, `docs:`, ...) -- release-drafter assembles release notes from them. Run `make setup` after cloning to install dev dependencies and the pre-commit hooks (including the AI-attribution-rejecting `commit-msg` hook).
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from netbox.plugins import PluginConfig
|
|
4
4
|
|
|
5
|
-
__version__ = "0.2.
|
|
5
|
+
__version__ = "0.2.1"
|
|
6
6
|
|
|
7
7
|
logger = logging.getLogger(__name__)
|
|
8
8
|
|
|
@@ -89,8 +89,12 @@ class NetBoxPathwaysConfig(PluginConfig):
|
|
|
89
89
|
|
|
90
90
|
super().ready()
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
from django.core.checks import register
|
|
93
|
+
|
|
93
94
|
from . import signals # noqa: F401
|
|
95
|
+
from .checks import check_geometry_column_srids
|
|
96
|
+
|
|
97
|
+
register(check_geometry_column_srids)
|
|
94
98
|
|
|
95
99
|
logger.info("%s plugin loaded", self.name)
|
|
96
100
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
System checks for the netbox_pathways plugin.
|
|
3
|
+
|
|
4
|
+
The storage SRID is baked into PostGIS columns at migrate time, but
|
|
5
|
+
get_srid() is read from PLUGINS_CONFIG at form/serializer save time. If
|
|
6
|
+
the two ever drift apart -- either because a migration shipped with a
|
|
7
|
+
hardcoded SRID, or because an operator edited PLUGINS_CONFIG after
|
|
8
|
+
applying migrations -- inserts fail with a SRID mismatch and crash the
|
|
9
|
+
end user back to the home page (see issue #5).
|
|
10
|
+
|
|
11
|
+
This module introspects geometry_columns and emits a checks.Error for
|
|
12
|
+
every column whose stored SRID does not match get_srid(), with a hint
|
|
13
|
+
that points at both remediation paths (revert config, or write an
|
|
14
|
+
ST_Transform migration).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from django.apps import apps
|
|
18
|
+
from django.core.checks import Error
|
|
19
|
+
from django.db import connection
|
|
20
|
+
from django.db.utils import OperationalError, ProgrammingError
|
|
21
|
+
|
|
22
|
+
from .geo import get_srid
|
|
23
|
+
|
|
24
|
+
CHECK_ID = "netbox_pathways.E001"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _introspect_column_srids(connection, app_label):
|
|
28
|
+
"""Return {(table, column): srid} for geometry columns in the app's tables."""
|
|
29
|
+
if connection.vendor != "postgresql":
|
|
30
|
+
return {}
|
|
31
|
+
try:
|
|
32
|
+
with connection.cursor() as cursor:
|
|
33
|
+
cursor.execute(
|
|
34
|
+
"SELECT f_table_name, f_geometry_column, srid FROM geometry_columns WHERE f_table_name LIKE %s",
|
|
35
|
+
[f"{app_label}_%"],
|
|
36
|
+
)
|
|
37
|
+
return {(row[0], row[1]): row[2] for row in cursor.fetchall()}
|
|
38
|
+
except (OperationalError, ProgrammingError):
|
|
39
|
+
return {}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def check_geometry_column_srids(app_configs=None, **kwargs):
|
|
43
|
+
"""Compare introspected column SRIDs to PLUGINS_CONFIG['netbox_pathways']['srid']."""
|
|
44
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
expected_srid = get_srid()
|
|
48
|
+
except ImproperlyConfigured:
|
|
49
|
+
return []
|
|
50
|
+
|
|
51
|
+
actual = _introspect_column_srids(connection, "netbox_pathways")
|
|
52
|
+
if not actual:
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
models = apps.get_app_config("netbox_pathways").get_models()
|
|
57
|
+
except LookupError:
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
errors = []
|
|
61
|
+
for model in models:
|
|
62
|
+
table = model._meta.db_table
|
|
63
|
+
for field in model._meta.get_fields():
|
|
64
|
+
if not hasattr(field, "srid") or field.srid is None:
|
|
65
|
+
continue
|
|
66
|
+
actual_srid = actual.get((table, field.column))
|
|
67
|
+
if actual_srid is None or actual_srid == expected_srid:
|
|
68
|
+
continue
|
|
69
|
+
errors.append(
|
|
70
|
+
Error(
|
|
71
|
+
f"Geometry column {table}.{field.column} has SRID {actual_srid}, "
|
|
72
|
+
f"but PLUGINS_CONFIG['netbox_pathways']['srid'] is {expected_srid}. "
|
|
73
|
+
"Form submissions and API writes will fail with 'Geometry SRID does "
|
|
74
|
+
"not match column SRID'.",
|
|
75
|
+
hint=(
|
|
76
|
+
"Storage SRID is immutable after migrations apply. Either "
|
|
77
|
+
f"set PLUGINS_CONFIG['netbox_pathways']['srid'] = {actual_srid} "
|
|
78
|
+
"to match the existing columns, or write a data migration that "
|
|
79
|
+
f"runs ST_Transform(<column>, {expected_srid}) on every affected "
|
|
80
|
+
"row before re-typing the column."
|
|
81
|
+
),
|
|
82
|
+
id=CHECK_ID,
|
|
83
|
+
obj=model,
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
return errors
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0004_circuit_geometry.py
RENAMED
|
@@ -7,6 +7,10 @@ import taggit.managers
|
|
|
7
7
|
import utilities.json
|
|
8
8
|
from django.db import migrations, models
|
|
9
9
|
|
|
10
|
+
from netbox_pathways.geo import get_srid
|
|
11
|
+
|
|
12
|
+
_SRID = get_srid()
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class Migration(migrations.Migration):
|
|
12
16
|
|
|
@@ -24,7 +28,7 @@ class Migration(migrations.Migration):
|
|
|
24
28
|
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
|
25
29
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
|
26
30
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
|
27
|
-
('path', django.contrib.gis.db.models.fields.LineStringField(srid=
|
|
31
|
+
('path', django.contrib.gis.db.models.fields.LineStringField(srid=_SRID)),
|
|
28
32
|
('provider_reference', models.CharField(blank=True, max_length=200)),
|
|
29
33
|
('comments', models.TextField(blank=True)),
|
|
30
34
|
('circuit', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='pathways_route', to='circuits.circuit')),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-pathways
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: NetBox plugin for physical cable plant infrastructure documentation with GIS capabilities
|
|
5
5
|
Author-email: Jonathan Senecal <contact@jonathansenecal.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/jsenecal/netbox-pathways
|
|
@@ -179,6 +179,13 @@ Full documentation: **[jsenecal.github.io/netbox-pathways](https://jsenecal.gith
|
|
|
179
179
|
- [Architecture](https://jsenecal.github.io/netbox-pathways/developer/architecture/)
|
|
180
180
|
- [GeoJSON API reference](https://jsenecal.github.io/netbox-pathways/reference/geojson-api/)
|
|
181
181
|
|
|
182
|
+
## Related plugins
|
|
183
|
+
|
|
184
|
+
netbox-pathways is part of a three-plugin set that models the full optical transport stack:
|
|
185
|
+
|
|
186
|
+
- **[netbox-fms](https://github.com/jsenecal/netbox-fms)** -- Fiber Management System. Defines fiber cable construction (buffer tubes, ribbons, strands), plans splices in closures, and provisions end-to-end fiber circuits. Pathways tracks *where cables run*; FMS tracks *what is inside them and how strands are spliced*.
|
|
187
|
+
- **[netbox-wdm](https://github.com/jsenecal/netbox-wdm)** -- WDM (Wavelength Division Multiplexing) device management. Models ITU channel plans, ROADM mappings, and wavelength services that ride on top of the fiber circuits FMS provisions, over the cables routed through Pathways.
|
|
188
|
+
|
|
182
189
|
## Contributing
|
|
183
190
|
|
|
184
191
|
PRs welcome. Use conventional-commits PR titles (`feat:`, `fix:`, `chore:`, `docs:`, ...) -- release-drafter assembles release notes from them. Run `make setup` after cloning to install dev dependencies and the pre-commit hooks (including the AI-attribution-rejecting `commit-msg` hook).
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
pyproject.toml
|
|
3
3
|
netbox_pathways/__init__.py
|
|
4
|
+
netbox_pathways/checks.py
|
|
4
5
|
netbox_pathways/choices.py
|
|
5
6
|
netbox_pathways/filterforms.py
|
|
6
7
|
netbox_pathways/filters.py
|
|
@@ -134,4 +135,5 @@ tests/test_map_view.py
|
|
|
134
135
|
tests/test_planned_route.py
|
|
135
136
|
tests/test_registry.py
|
|
136
137
|
tests/test_route_engine.py
|
|
137
|
-
tests/test_routing.py
|
|
138
|
+
tests/test_routing.py
|
|
139
|
+
tests/test_srid_checks.py
|
|
@@ -16,7 +16,7 @@ netbox_pathways = [
|
|
|
16
16
|
|
|
17
17
|
[project]
|
|
18
18
|
name = "netbox-pathways"
|
|
19
|
-
version = "0.2.
|
|
19
|
+
version = "0.2.1"
|
|
20
20
|
description = "NetBox plugin for physical cable plant infrastructure documentation with GIS capabilities"
|
|
21
21
|
readme = "README.md"
|
|
22
22
|
authors = [
|
|
@@ -60,7 +60,7 @@ Tracker = "https://github.com/jsenecal/netbox-pathways/issues"
|
|
|
60
60
|
Documentation = "https://jsenecal.github.io/netbox-pathways/"
|
|
61
61
|
|
|
62
62
|
[tool.bumpversion]
|
|
63
|
-
current_version = "0.2.
|
|
63
|
+
current_version = "0.2.1"
|
|
64
64
|
commit = true
|
|
65
65
|
tag = true
|
|
66
66
|
tag_name = "v{new_version}"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Tests for SRID drift system check and migration consistency."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from unittest.mock import MagicMock, patch
|
|
6
|
+
|
|
7
|
+
from django.core.checks import Error
|
|
8
|
+
from django.db import connection
|
|
9
|
+
from django.db.utils import ProgrammingError
|
|
10
|
+
|
|
11
|
+
from netbox_pathways.checks import (
|
|
12
|
+
_introspect_column_srids,
|
|
13
|
+
check_geometry_column_srids,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestMigrationSrid:
|
|
18
|
+
"""Migrations must derive SRID from get_srid(), never from a literal."""
|
|
19
|
+
|
|
20
|
+
def test_circuit_geometry_path_srid_follows_config(self, settings):
|
|
21
|
+
settings.PLUGINS_CONFIG = deepcopy(settings.PLUGINS_CONFIG)
|
|
22
|
+
settings.PLUGINS_CONFIG.setdefault("netbox_pathways", {})["srid"] = 3857
|
|
23
|
+
|
|
24
|
+
mod = importlib.import_module("netbox_pathways.migrations.0004_circuit_geometry")
|
|
25
|
+
importlib.reload(mod)
|
|
26
|
+
|
|
27
|
+
operation = mod.Migration.operations[0]
|
|
28
|
+
fields_dict = dict(operation.fields)
|
|
29
|
+
assert fields_dict["path"].srid == 3857
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestIntrospectColumnSrids:
|
|
33
|
+
def test_returns_empty_for_non_postgres(self):
|
|
34
|
+
fake_conn = MagicMock()
|
|
35
|
+
fake_conn.vendor = "sqlite"
|
|
36
|
+
assert _introspect_column_srids(fake_conn, "netbox_pathways") == {}
|
|
37
|
+
|
|
38
|
+
def test_returns_empty_on_db_error(self):
|
|
39
|
+
fake_conn = MagicMock()
|
|
40
|
+
fake_conn.vendor = "postgresql"
|
|
41
|
+
cursor = fake_conn.cursor.return_value.__enter__.return_value
|
|
42
|
+
cursor.execute.side_effect = ProgrammingError("relation does not exist")
|
|
43
|
+
assert _introspect_column_srids(fake_conn, "netbox_pathways") == {}
|
|
44
|
+
|
|
45
|
+
def test_introspects_real_columns(self, db):
|
|
46
|
+
result = _introspect_column_srids(connection, "netbox_pathways")
|
|
47
|
+
assert ("netbox_pathways_structure", "location") in result
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestCheckGeometryColumnSrids:
|
|
51
|
+
def test_silent_when_srid_unconfigured(self):
|
|
52
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
53
|
+
|
|
54
|
+
with patch("netbox_pathways.checks.get_srid", side_effect=ImproperlyConfigured()):
|
|
55
|
+
assert check_geometry_column_srids() == []
|
|
56
|
+
|
|
57
|
+
def test_silent_when_no_columns_introspected(self):
|
|
58
|
+
with patch("netbox_pathways.checks._introspect_column_srids", return_value={}):
|
|
59
|
+
assert check_geometry_column_srids() == []
|
|
60
|
+
|
|
61
|
+
def test_no_errors_when_columns_match_config(self, db):
|
|
62
|
+
assert check_geometry_column_srids() == []
|
|
63
|
+
|
|
64
|
+
def test_reports_error_on_mismatch(self, db):
|
|
65
|
+
with patch("netbox_pathways.checks.get_srid", return_value=999):
|
|
66
|
+
errors = check_geometry_column_srids()
|
|
67
|
+
assert errors, "expected at least one mismatch error"
|
|
68
|
+
assert all(isinstance(e, Error) for e in errors)
|
|
69
|
+
assert all(e.id == "netbox_pathways.E001" for e in errors)
|
|
70
|
+
first = errors[0]
|
|
71
|
+
assert "999" in first.msg
|
|
72
|
+
assert "PLUGINS_CONFIG" in first.hint
|
|
73
|
+
assert "ST_Transform" in first.hint
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/management/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0010_structure_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/migrations/0013_plannedroute.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways/templates/netbox_pathways/map.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_pathways-0.2.0 → netbox_pathways-0.2.1}/netbox_pathways.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|