Skip to content

Commit 674d7f1

Browse files
authored
Merge pull request #86 from jasonyates/refactoring
Refactor plugin to support generic model relationships
2 parents 7c75d0f + 4dd7602 commit 674d7f1

48 files changed

Lines changed: 1386 additions & 3612 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/publish.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
id-token: write # Required for trusted publishing
13+
contents: write # Required for creating GitHub releases
14+
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: '3.12'
23+
24+
- name: Install build tools
25+
run: pip install build
26+
27+
- name: Extract version
28+
id: version
29+
run: echo "version=$(sed -n "s/^ version = '\(.*\)'/\1/p" netbox_documents/__init__.py | head -1)" >> $GITHUB_OUTPUT
30+
31+
- name: Build package
32+
run: python -m build
33+
34+
- name: Publish to PyPI
35+
uses: pypa/gh-action-pypi-publish@release/v1
36+
37+
- name: Create GitHub Release
38+
uses: softprops/action-gh-release@v2
39+
with:
40+
tag_name: v${{ steps.version.outputs.version }}
41+
name: v${{ steps.version.outputs.version }}
42+
generate_release_notes: true
43+
files: dist/*

CLAUDE.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What This Is
6+
7+
A NetBox plugin (`netbox-documents`) that attaches documents and external URLs to any NetBox object. It uses a single `Document` model with Django's ContentType framework (GenericForeignKey) to relate documents to any model. Requires NetBox 4.3+.
8+
9+
## Development Environment
10+
11+
This plugin runs inside a NetBox installation. You need a working NetBox dev environment to run migrations or tests. The plugin is installed into NetBox's virtualenv:
12+
13+
```bash
14+
source /opt/netbox/venv/bin/activate
15+
pip install -e /path/to/netbox-documents
16+
python manage.py migrate netbox_documents
17+
python manage.py runserver
18+
```
19+
20+
## Testing
21+
22+
Tests use Django's TestCase framework. Run from the NetBox project directory:
23+
24+
```bash
25+
python manage.py test netbox_documents
26+
python manage.py test netbox_documents.tests.test_models # single module
27+
python manage.py test netbox_documents.tests.test_models.DocumentModelTest # single class
28+
python manage.py test netbox_documents.tests.test_models.DocumentModelTest.test_create_document_with_file # single test
29+
```
30+
31+
## Building for PyPI
32+
33+
```bash
34+
pip install build twine
35+
python -m build
36+
twine upload dist/*
37+
```
38+
39+
## Architecture
40+
41+
The plugin follows NetBox's plugin conventions. All code lives in `netbox_documents/`.
42+
43+
**Core model** (`models.py`): Single `Document` model with GenericForeignKey (`content_type` + `object_id`). `DocTypeChoices` is built dynamically at import time from built-in types + user-configured `custom_doc_types`. The `get_allowed_doc_types()` helper resolves per-model type filtering from plugin settings.
44+
45+
**How documents appear on object pages** (`template_content.py`): A factory function creates a `PluginTemplateExtension` class for each supported model (Site, Device, Circuit, etc.). Each extension renders `document_include.html` on the object's detail page. The panel placement (left/right) is controlled by the `documents_location` setting.
46+
47+
**How documents are created**: Documents are always added from an object's detail page, never from a standalone form. The "Add Document" link passes `?content_type=X&object_id=Y` as URL params. The view's `alter_object()` method reads these params and sets them on the instance before the form renders. The form itself (`forms.py`) only contains document-specific fields (name, file/URL, type, comments, tags) -- not the object association.
48+
49+
**API** (`api/`): Single `DocumentViewSet` at `/api/plugins/netbox-documents/documents/`. Uses `ContentTypeField` for the `content_type` field and accepts `object_id` as an integer.
50+
51+
**Configuration** (`__init__.py`): Plugin settings include `documents_location` (left/right panel), `custom_doc_types` (user-defined types as `(value, label, color)` tuples), and `allowed_doc_types` (per-model type filtering with `__all__` fallback key).
52+
53+
## Key Patterns
54+
55+
- Views extend NetBox's generic views (`ObjectView`, `ObjectListView`, `ObjectEditView`, `ObjectDeleteView`, `BulkDeleteView`) which handle permissions automatically.
56+
- Template buttons in `document_include.html` are gated with `{% if perms.netbox_documents.* %}` checks.
57+
- The `file_upload()` utility in `utils.py` generates upload paths using `object_id` as a prefix.
58+
- Navigation menu (`navigation.py`) is conditionally created based on the `enable_navigation_menu` setting.
59+
- Search index (`search.py`) registers `Document` for NetBox's global search.
60+
61+
## Dependencies
62+
63+
Runtime: `drf_extra_fields>=3.7.0` (provides `Base64FileField` for API file uploads)

0 commit comments

Comments
 (0)