mirror of
https://github.com/netbox-community/netbox.git
synced 2026-04-11 11:47:08 +02:00
* #21701 allow upload script via API
* #21701 allow upload script via API
* add extra test
* change to use Script api endpoint
* ruff fix
* review feedback:
* review feedback:
* review feedback:
* Fix permission check, perform_create delegation, and test mock setup
- destroy() now checks extras.delete_script (queryset is Script.objects.all())
- create() delegates to self.perform_create() instead of calling serializer.save() directly
- Add comment explaining why update/partial_update intentionally return 405
- Fix test_upload_script_module: set mock_storage.save.return_value so file_path
receives a real string after the _save_upload return-value fix; add DB existence check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Return 400 instead of 500 on duplicate script module upload
Catch IntegrityError from the unique (file_root, file_path) constraint
and re-raise as a ValidationError so the API returns a 400 with a clear
message rather than a 500.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Validate upload_file + data_source conflict for multipart requests
DRF 3.16 Serializer.get_value() uses parse_html_dict() or empty for all
HTML/multipart input. A flat key like data_source=2 produces an empty
dict ({}), which is falsy, so it falls back to empty and the nested
field is silently skipped. data.get('data_source') is therefore always
None in multipart requests, bypassing the conflict check.
Fix: also check self.initial_data for data_source and data_file in all
three guards in validate(), so the raw submitted value is detected even
when DRF's HTML parser drops the deserialized object.
Add test_upload_with_data_source_fails to cover the multipart conflict
path explicitly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Require data_file when data_source is specified
data_source alone is not a valid creation payload — a data_file must
also be provided to identify which file within the source to sync.
Add the corresponding validation error and a test to cover the case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Align ManagedFileForm validation with API serializer rules
Add the missing checks to ManagedFileForm.clean():
- upload_file + data_source is rejected (matches API)
- data_source without data_file is rejected with a specific message
- Update the 'nothing provided' error to mention data source + data file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Revert "Align ManagedFileForm validation with API serializer rules"
This reverts commit f0ac7c3bd2.
* Align API validation messages with UI; restore complete checks
- Match UI error messages for upload+data_file conflict and no-source case
- Keep API-only guards for upload+data_source and data_source-without-data_file
- Restore test_upload_with_data_source_fails
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Run source/file conflict checks before super().validate() / full_clean()
super().validate() calls full_clean() on the model instance, which raises
a unique-constraint error for (file_root, file_path) when file_path is
empty (e.g. data_source-only requests). Move the conflict guards above the
super() call so they produce clear, actionable error messages before
full_clean() has a chance to surface confusing database-level errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* destroy() deletes ScriptModule, not Script
DELETE /api/extras/scripts/<pk>/ now deletes the entire ScriptModule
(matching the UI's delete view), including modules with no Script
children (e.g. sync hasn't run yet). Permission check updated to
delete_scriptmodule. The queryset restriction for destroy is removed
since the module is deleted via script.module, not super().destroy().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* review feedback:
* cleanup
* cleanup
* cleanup
* cleanup
* change to ScriptModule
* change to ScriptModule
* change to ScriptModule
* update docs
* cleanup
* restore file
* cleanup
* cleanup
* cleanup
* cleanup
* cleanup
* keep only upload functionality
* cleanup
* cleanup
* cleanup
* change to scripts/upload api
* cleanup
* cleanup
* cleanup
* cleanup
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
37 lines
1.6 KiB
Python
37 lines
1.6 KiB
Python
from django.urls import include, path
|
|
|
|
from netbox.api.routers import NetBoxRouter
|
|
|
|
from . import views
|
|
|
|
router = NetBoxRouter()
|
|
router.APIRootView = views.ExtrasRootView
|
|
|
|
router.register('event-rules', views.EventRuleViewSet)
|
|
router.register('webhooks', views.WebhookViewSet)
|
|
router.register('custom-fields', views.CustomFieldViewSet)
|
|
router.register('custom-field-choice-sets', views.CustomFieldChoiceSetViewSet)
|
|
router.register('custom-links', views.CustomLinkViewSet)
|
|
router.register('export-templates', views.ExportTemplateViewSet)
|
|
router.register('saved-filters', views.SavedFilterViewSet)
|
|
router.register('table-configs', views.TableConfigViewSet)
|
|
router.register('bookmarks', views.BookmarkViewSet)
|
|
router.register('notifications', views.NotificationViewSet)
|
|
router.register('notification-groups', views.NotificationGroupViewSet)
|
|
router.register('subscriptions', views.SubscriptionViewSet)
|
|
router.register('tags', views.TagViewSet)
|
|
router.register('tagged-objects', views.TaggedItemViewSet)
|
|
router.register('image-attachments', views.ImageAttachmentViewSet)
|
|
router.register('journal-entries', views.JournalEntryViewSet)
|
|
router.register('config-contexts', views.ConfigContextViewSet)
|
|
router.register('config-context-profiles', views.ConfigContextProfileViewSet)
|
|
router.register('config-templates', views.ConfigTemplateViewSet)
|
|
router.register('scripts/upload', views.ScriptModuleViewSet)
|
|
router.register('scripts', views.ScriptViewSet, basename='script')
|
|
|
|
app_name = 'extras-api'
|
|
urlpatterns = [
|
|
path('dashboard/', views.DashboardView.as_view(), name='dashboard'),
|
|
path('', include(router.urls)),
|
|
]
|