diff --git a/README.rst b/README.rst
index b94cfbf..1f5ab87 100644
--- a/README.rst
+++ b/README.rst
@@ -1,817 +1,61 @@
-=============
openwisp-ipam
=============
.. image:: https://github.com/openwisp/openwisp-ipam/actions/workflows/ci.yml/badge.svg?branch=master
- :target: https://github.com/openwisp/openwisp-ipam/actions/workflows/ci.yml?query=workflow%3AOpenWISP+Ipam+CI+Build%22
- :alt: CI Build status
+ :target: https://github.com/openwisp/openwisp-ipam/actions/workflows/ci.yml?query=workflow%3AOpenWISP+Ipam+CI+Build%22
+ :alt: CI Build status
.. image:: https://coveralls.io/repos/openwisp/openwisp-ipam/badge.svg
- :target: https://coveralls.io/r/openwisp/openwisp-ipam
- :alt: Coverage
+ :target: https://coveralls.io/r/openwisp/openwisp-ipam
+ :alt: Coverage
.. image:: https://img.shields.io/pypi/v/openwisp-ipam
- :target: https://pypi.org/project/openwisp-ipam
- :alt: PyPI
+ :target: https://pypi.org/project/openwisp-ipam
+ :alt: PyPI
.. image:: https://img.shields.io/librariesio/release/github/openwisp/openwisp-ipam
- :target: https://libraries.io/github/openwisp/openwisp-ipam#dependencies
- :alt: Dependency monitoring
+ :target: https://libraries.io/github/openwisp/openwisp-ipam#dependencies
+ :alt: Dependency monitoring
.. image:: https://github.com/openwisp/openwisp-ipam/raw/docs/docs/subnet_demo.gif
- :alt: Feature Highlights
-
-.. contents:: **Table of Contents**:
- :backlinks: none
- :depth: 2
-
-Available Features
-******************
-
-* IPv4 and IPv6 IP address management
-* IPv4 and IPv6 Subnet management
-* Automatic free space display for all subnets
-* Visual display for a specific subnet
-* IP request module
-* REST API for CRUD operations and main features
-* Possibility to search for an IP or subnet
-* CSV Import and Export of subnets and their IPs
-
-Project Goals
-*************
-
-* provide basic features of IP Address management as a reusable django app
-* integrate this module in the rest of the OpenWISP ecosystem
-* allow standalone usage (without the rest of OpenWISP)
-* provide ways to extended the core features in order to create derivatives
-
-Dependencies
-************
-
-* Python 3.8 or higher
-* Django 3.2 or higher (except 4.0)
-* Django REST Framework (for the REST API)
-* openwisp-users
-* swapper
-
-Install stable version
-**********************
-
-.. code-block:: shell
-
- pip install openwisp-ipam
-
-Install development version
-***************************
-
-Install tarball:
-
-.. code-block:: shell
-
- pip install https://github.com/openwisp/openwisp-ipam/tarball/master
-
-Alternatively you can install via pip using git:
-
-.. code-block:: shell
-
- pip install -e git+git://github.com/openwisp/openwisp-ipam#egg=openwisp-ipam
-
-Installation for development
-****************************
-
-Install ``openwisp-ipam`` for development using following commands:
-
-.. code-block:: shell
-
- git clone https://github.com/openwisp/openwisp-ipam.git
- cd openwisp-ipam
- pip install -e .
- pip install -r requirements-test.txt
-
-Launch the development sever:
-
-.. code-block:: shell
-
- cd tests/
- ./manage.py migrate
- ./manage.py createsuperuser
- ./manage.py runserver
-
-You can access the admin interface at `http://127.0.0.1:8000/admin/`.
-
-Run Tests
-=========
-
-Install test requirements:
-
-.. code-block:: shell
-
- pip install -r requirements-test.txt
-
-Then run the test suite:
-
-.. code-block:: shell
-
- # options "--keepdb" & "--parallel" are optional but
- # improve time required for running tests.
- ./runtests.py --keepdb --parallel
- # Run tests for the sample_app
- SAMPLE_APP=1 ./runtests.py --keepdb --parallel
-
-Visual Display of subnets
-*************************
-
-openwisp-ipam provides a graphical representation of a subnet which shows the available free space under any subnet.
-
-.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/visual-display.png
-
-REST API
-********
-
-Live documentation
-==================
-
-.. image:: https://github.com/openwisp/openwisp-ipam/raw/docs/docs/api-docs.png
-
-A general live API documentation (following the OpenAPI specification) is available at ``/api/v1/docs/``.
-
-Browsable web interface
-=======================
-
-.. image:: https://github.com/openwisp/openwisp-ipam/raw/docs/docs/api-ui.png
-
-Additionally, opening any of the endpoints `listed below <#list-of-endpoints>`_
-directly in the browser will show the `browsable API interface of Django-REST-Framework
-`_,
-which makes it even easier to find out the details of each endpoint.
-
-Authentication
-==============
-
-See openwisp-users: `authenticating with the user token
-`_.
-
-When browsing the API via the `Live documentation <#live-documentation>`_
-or the `Browsable web page <#browsable-web-interface>`_, you can also use
-the session authentication by logging in the django admin.
-
-Pagination
-==========
-
-All *list* endpoints support the ``page_size`` parameter that allows paginating
-the results in conjunction with the ``page`` parameter.
-
-.. code-block:: text
-
- GET /api/v1//?page_size=10
- GET /api/v1//?page_size=10&page=2
-
-List of endpoints
-=================
-
-Since the detailed explanation is contained in the `Live documentation <#live-documentation>`_
-and in the `Browsable web page <#browsable-web-interface>`_ of each endpoint,
-here we'll provide just a list of the available endpoints,
-for further information please open the URL of the endpoint in your browser.
-
-API Throttling
-==============
-
-To override the default API throttling settings, add the following to your ``settings.py`` file:
-
-.. code-block:: python
-
- REST_FRAMEWORK = {
- 'DEFAULT_THROTTLE_RATES': {
- 'ipam': '100/hour',
- }
- }
-
-The rate descriptions used in ``DEFAULT_THROTTLE_RATES`` may include
-``second``, ``minute``, ``hour`` or ``day`` as the throttle period.
-
-Get Next Available IP
-=====================
-
-A model method to fetch the next available IP address under a specific subnet. This method can also be accessed via a REST API: `openwisp_ipam/base/models.py `_
-
-GET
----
-
-Returns the next available IP address under a subnet.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//get-next-available-ip/
-
-Request IP
-^^^^^^^^^^
-
-A model method to create and fetch the next available IP address record under a subnet.
-
-POST
-----
-
-Creates a record for next available IP address and returns JSON data of that record.
-
-.. code-block:: text
-
- POST /api/v1/ipam/subnet//request-ip/
-
-=========== ========================================
-Param Description
-=========== ========================================
-description Optional description for the IP address
-=========== ========================================
-
-Response
-^^^^^^^^
-
-.. code-block:: json
-
-
- {
- "ip_address": "ip_address",
- "subnet": "subnet_uuid",
- "description": "optional description"
- }
-
-
-IpAddress-Subnet List and Create View
-=====================================
-
-An api endpoint to retrieve or create IP addresses under a specific subnet.
-
-GET
----
-
-Returns the list of IP addresses under a particular subnet.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//ip-address/
-
-POST
-----
-
-Create a new ``IP Address``.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//ip-address/
-
-=========== ========================================
-Param Description
-=========== ========================================
-ip_address IPv6/IPv4 address value
-subnet Subnet UUID
-description Optional description for the IP address
-=========== ========================================
-
-Subnet List/Create View
-=======================
-
-An api endpoint to create or retrieve the list of subnet instances.
-
-GET
----
-
-Returns the list of ``Subnet`` instances.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet/
-
-POST
-----
-
-Create a new ``Subnet``.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet/
-
-============= ========================================
-Param Description
-============= ========================================
-subnet Subnet value in CIDR format
-master_subnet Master Subnet UUID
-description Optional description for the IP address
-============= ========================================
-
-Subnet View
-===========
-
-An api endpoint for retrieving, updating or deleting a subnet instance.
-
-GET
----
-
-Get details of a ``Subnet`` instance
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//
-
-DELETE
-------
-
-Delete a ``Subnet`` instance
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//
-
-PUT
----
-
-Update details of a ``Subnet`` instance.
-
-.. code-block:: text
-
- /api/v1/ipam/subnet//
-
-============= ========================================
-Param Description
-============= ========================================
-subnet Subnet value in CIDR format
-master_subnet Master Subnet UUID
-description Optional description for the IP address
-============= ========================================
-
-IP Address View
-===============
-
-An api endpoint for retrieving, updating or deleting a IP address instance.
-
-GET
----
-
-Get details of an ``IP address`` instance.
-
-.. code-block:: text
-
- /api/v1/ipam/ip-address//
-
-DELETE
-------
-
-Delete an ``IP address`` instance.
-
-.. code-block:: text
-
- /api/v1/ipam/ip-address//
-
-PUT
----
-
-Update details of an ``IP address`` instance.
-
-.. code-block:: text
-
- /api/v1/ipam/ip-address//
-
-=========== ========================================
-Param Description
-=========== ========================================
-ip_address IPv6/IPv4 value
-subnet Subnet UUID
-description Optional description for the IP address
-=========== ========================================
-
-Export Subnet View
-==================
+ :alt: Feature Highlights
-View to export subnet data.
+For a complete overview of features, refer to the `IPAM: Features
+`_ section of the
+OpenWISP documentation.
-POST
-----
+Documentation
+-------------
-.. code-block:: text
+- `Developer documentation
+ `_
+- `User documentation `_
- /api/v1/ipam/subnet//export/
-
-Import Subnet View
-==================
-
-View to import subnet data.
-
-POST
-----
-
-.. code-block:: text
-
- /api/v1/ipam/import-subnet/
-
-
-Exporting and Importing Subnet
-==============================
-
-One can easily import and export `Subnet` data and it's Ip Addresses using `openwisp-ipam`.
-This works for both IPv4 and IPv6 types of networks.
-
-Exporting
+Changelog
---------
-Data can be exported via the admin interface or by using a management command. The exported data is in `.csv` file format.
-
-From management command
-^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: shell
-
- ./manage.py export_subnet
+See `Change log
+`__.
-This would export the subnet if it exists on the database.
+Contributing
+------------
-From admin interface
-^^^^^^^^^^^^^^^^^^^^
+Please refer to the `OpenWISP contributing guidelines
+`_.
-Data can be exported from the admin interface by just clicking on the export button on the subnet's admin change view.
+Support
+-------
-.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/export.png
+See `OpenWISP Support Channels `_.
-Importing
+Changelog
---------
-Data can be imported via the admin interface or by using a management command.
-The imported data file can be in `.csv` and `.xlsx` format. While importing
-data for ip addresses, the system checks if the subnet specified in the import file exists or not.
-If the subnet does not exists it will be created while importing data.
-
-From management command
-^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: shell
-
- ./manage.py import_subnet --file=
-
-From admin interface
-^^^^^^^^^^^^^^^^^^^^
-
-Data can be imported from the admin interface by just clicking on the import button on the subnet view.
-
-.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/import.png
-
-CSV file format
-===============
-
-Follow the following structure while creating `csv` file to import data.
-
-.. code-block:: text
-
- Subnet Name
- Subnet Value
- Organization Slug
-
- ip_address,description
- ,
- ,
- ,
-
-Setup (integrate in an existing Django project)
-***********************************************
-
-The ``settings.py`` of your project should contain the following:
-
-.. code-block:: python
-
- INSTALLED_APPS = [
- # openwisp2 modules
- 'openwisp_users',
- 'openwisp_ipam',
- # admin
- 'admin_auto_filters',
- 'django.contrib.admin',
- # rest framework
- 'rest_framework',
- 'drf_yasg',
- ]
-
- AUTH_USER_MODEL = 'openwisp_users.User'
-
-Add the URLs to your main ``urls.py``:
-
-.. code-block:: python
-
- from django.contrib import admin
- from django.urls import include, path
- from openwisp_users.api.urls import get_api_urls as get_users_api_urls
-
- urlpatterns = [
- # admin URLs
- path('admin/', admin.site.urls),
- # IPAM API
- path('', include('openwisp_ipam.urls')),
- # OpenAPI docs
- path('api/v1/', include('openwisp_utils.api.urls')),
- # Bearer Authentication API URL
- path('api/v1/', include((get_users_api_urls(), 'users'), namespace='users')),
- ]
-
-
-Then run:
-
-.. code-block:: shell
-
- ./manage.py migrate
-
-Extending openwisp-ipam
-***********************
-
-One of the core values of the OpenWISP project is `Software Reusability `_,
-for this reason *openwisp-ipam* provides a set of base classes
-which can be imported, extended and reused to create derivative apps.
-
-In order to implement your custom version of *openwisp-ipam*,
-you need to perform the steps described in this section.
-
-When in doubt, the code in the `test project `_ and
-the `sample app `_
-will serve you as source of truth:
-just replicate and adapt that code to get a basic derivative of
-*openwisp-ipam* working.
-
-If you want to add new users fields, please follow the `tutorial to extend the
-openwisp-users `_.
-As an example, we have extended *openwisp-users* to *sample_users* app and
-added a field ``social_security_number`` in the `sample_users/models.py
-`_.
-
-**Premise**: if you plan on using a customized version of this module,
-we suggest to start with it since the beginning, because migrating your data
-from the default module to your extended version may be time consuming.
-
-1. Initialize your custom module
-================================
-
-The first thing you need to do is to create a new django app which will
-contain your custom version of *openwisp-ipam*.
-
-A django app is nothing more than a
-`python package `_
-(a directory of python scripts), in the following examples we'll call this django app
-``myipam``, but you can name it how you want::
-
- django-admin startapp myipam
-
-Keep in mind that the command mentioned above must be called from a directory
-which is available in your `PYTHON_PATH `_
-so that you can then import the result into your project.
-
-Now you need to add ``myipam`` to ``INSTALLED_APPS`` in your ``settings.py``,
-ensuring also that ``openwisp_ipam`` has been removed:
-
-.. code-block:: python
-
- INSTALLED_APPS = [
- # ... other apps ...
- 'openwisp_utils.admin_theme',
- # all-auth
- 'django.contrib.sites',
- 'allauth',
- 'allauth.account',
- 'allauth.socialaccount',
- # openwisp2 modules
- 'openwisp_users',
- # 'myipam', <-- replace without your app-name here
- # admin
- 'admin_auto_filters',
- 'django.contrib.admin',
- # rest framework
- 'rest_framework',
- # Other dependencies
- 'reversion',
- ]
-
-For more information about how to work with django projects and django apps,
-please refer to the `django documentation `_.
-
-2. Install ``openwisp-ipam``
-============================
-
-Install (and add to the requirement of your project) openwisp-ipam::
-
- pip install openwisp-ipam
-
-3. Add ``EXTENDED_APPS``
-========================
-
-Add the following to your ``settings.py``:
-
-.. code-block:: python
-
- EXTENDED_APPS = ('openwisp_ipam',)
-
-4. Add ``openwisp_utils.staticfiles.DependencyFinder``
-======================================================
-
-Add ``openwisp_utils.staticfiles.DependencyFinder`` to
-``STATICFILES_FINDERS`` in your ``settings.py``:
-
-.. code-block:: python
-
- STATICFILES_FINDERS = [
- 'django.contrib.staticfiles.finders.FileSystemFinder',
- 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
- 'openwisp_utils.staticfiles.DependencyFinder',
- ]
-
-5. Add ``openwisp_utils.loaders.DependencyLoader``
-==================================================
-
-Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES``
-in your ``settings.py``, but ensure it comes before
-``django.template.loaders.app_directories.Loader``:
-
-.. code-block:: python
-
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'OPTIONS': {
- 'loaders': [
- 'django.template.loaders.filesystem.Loader',
- 'openwisp_utils.loaders.DependencyLoader',
- 'django.template.loaders.app_directories.Loader',
- ],
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- }
- ]
-
-6. Inherit the AppConfig class
-==============================
-
-Please refer to the following files in the sample app of the test project:
-
-- `sample_ipam/__init__.py `_.
-- `sample_ipam/apps.py `_.
-
-You have to replicate and adapt that code in your project.
-
-For more information regarding the concept of ``AppConfig`` please refer to
-the `"Applications" section in the django documentation `_.
-
-7. Create your custom models
-============================
-
-For the purpose of showing an example, we added a simple "details" field to the
-`models of the sample app in the test project `_.
-
-You can add fields in a similar way in your ``models.py`` file.
-
-**Note**: for doubts regarding how to use, extend or develop models please refer to
-the `"Models" section in the django documentation `_.
-
-8. Add swapper configurations
-=============================
-
-Once you have created the models, add the following to your ``settings.py``:
-
-.. code-block:: python
-
- # Setting models for swapper module
- OPENWISP_IPAM_IPADDRESS_MODEL = 'myipam.IpAddress'
- OPENWISP_IPAM_SUBNET_MODEL = 'myipam.Subnet'
-
-Substitute ``myipam`` with the name you chose in step 1.
-
-9. Create database migrations
-=============================
-
-Create and apply database migrations::
-
- ./manage.py makemigrations
- ./manage.py migrate
-
-For more information, refer to the
-`"Migrations" section in the django documentation `_.
-
-
-10. Create the admin
-====================
-
-Refer to the `admin.py file of the sample app `_.
-
-To introduce changes to the admin, you can do it in two main ways which are described below.
-
-**Note**: for more information regarding how the django admin works, or how it can be customized,
-please refer to `"The django admin site" section in the django documentation `_.
-
-1. Monkey patching
-------------------
-
-If the changes you need to add are relatively small, you can resort to monkey patching.
-
-For example:
-
-.. code-block:: python
-
- from openwisp_ipam.admin import IpAddressAdmin, SubnetAdmin
-
- SubnetAdmin.app_label = 'sample_ipam'
-
-
-2. Inheriting admin classes
----------------------------
-
-If you need to introduce significant changes and/or you don't want to resort to
-monkey patching, you can proceed as follows:
-
-.. code-block:: python
-
- from django.contrib import admin
- from openwisp_ipam.admin import (
- IpAddressAdmin as BaseIpAddressAdmin,
- SubnetAdmin as BaseSubnetAdmin,
- )
- from swapper import load_model
-
- IpAddress = load_model('openwisp_ipam', 'IpAddress')
- Subnet = load_model('openwisp_ipam', 'Subnet')
-
- admin.site.unregister(IpAddress)
- admin.site.unregister(Subnet)
-
- @admin.register(IpAddress)
- class IpAddressAdmin(BaseIpAddressAdmin):
- # add your changes here
-
- @admin.register(Subnet)
- class SubnetAdmin(BaseSubnetAdmin):
- app_label = 'myipam'
- # add your changes here
-
-Substitute ``myipam`` with the name you chose in step 1.
-
-11. Create root URL configuration
-=================================
-
-.. code-block:: python
-
- from .sample_ipam import views as api_views
- from openwisp_ipam.urls import get_urls
-
- urlpatterns = [
- # ... other urls in your project ...
- # openwisp-ipam urls
- # path('', include(get_urls(api_views))) <-- Use only when changing API views (dicussed below)
- path('', include('openwisp_ipam.urls')),
- ]
-
-For more information about URL configuration in django, please refer to the
-`"URL dispatcher" section in the django documentation `_.
-
-12. Import the automated tests
-==============================
-
-When developing a custom application based on this module, it's a good
-idea to import and run the base tests too, so that you can be sure the changes
-you're introducing are not breaking some of the existing features of *openwisp-ipam*.
-
-In case you need to add breaking changes, you can overwrite the tests defined
-in the base classes to test your own behavior.
-
-See the `tests of the sample app `_
-to find out how to do this.
-
-You can then run tests with::
-
- # the --parallel flag is optional
- ./manage.py test --parallel myipam
-
-Substitute ``myipam`` with the name you chose in step 1.
-
-For more information about automated tests in django, please refer to
-`"Testing in Django" `_.
-
-Other base classes that can be inherited and extended
-=====================================================
-
-The following steps are not required and are intended for more advanced customization.
-
-1. Extending the API Views
---------------------------
-
-The API view classes can be extended into other django applications as well. Note
-that it is not required for extending openwisp-ipam to your app and this change
-is required only if you plan to make changes to the API views.
-
-Create a view file as done in `views.py `_.
-
-For more information about django views, please refer to the `views section in the django documentation `_.
-
-Contributing
-************
+See `CHANGES
+`_.
-Please refer to the `OpenWISP contributing guidelines `_.
+License
+-------
-`Support channels `_ |
-`Issue Tracker `_ |
-`License `_
+See `LICENSE
+`_.
diff --git a/docs/developer/extending.rst b/docs/developer/extending.rst
new file mode 100644
index 0000000..3257d6a
--- /dev/null
+++ b/docs/developer/extending.rst
@@ -0,0 +1,332 @@
+Extending OpenWISP IPAM
+=======================
+
+.. include:: ../partials/developer-docs.rst
+
+One of the core values of the OpenWISP project is :ref:`Software
+Reusability `, for this reason
+*openwisp-ipam* provides a set of base classes which can be imported,
+extended and reused to create derivative apps.
+
+In order to implement your custom version of *openwisp-ipam*, you need to
+perform the steps described in this section.
+
+When in doubt, the code in the `test project
+`_
+and the `sample app
+`_
+will serve you as source of truth: just replicate and adapt that code to
+get a basic derivative of *openwisp-ipam* working.
+
+If you want to add new users fields, please follow the :doc:`tutorial to
+extend the openwisp-users `. As an example, we
+have extended *openwisp-users* to *sample_users* app and added a field
+``social_security_number`` in the `sample_users/models.py
+`_.
+
+.. important::
+
+ If you plan on using a customized version of this module, we suggest
+ to start with it since the beginning, because migrating your data from
+ the default module to your extended version may be time consuming.
+
+.. contents:: **Table of Contents**:
+ :depth: 2
+ :local:
+
+1. Initialize your Custom Module
+--------------------------------
+
+The first thing you need to do is to create a new django app which will
+contain your custom version of *openwisp-ipam*.
+
+A django app is nothing more than a `python package
+`_ (a directory
+of python scripts), in the following examples we'll call this django app
+``myipam``, but you can name it how you want:
+
+.. code-block::
+
+ django-admin startapp myipam
+
+Keep in mind that the command mentioned above must be called from a
+directory which is available in your `PYTHON_PATH
+`_ so that
+you can then import the result into your project.
+
+Now you need to add ``myipam`` to ``INSTALLED_APPS`` in your
+``settings.py``, ensuring also that ``openwisp_ipam`` has been removed:
+
+.. code-block:: python
+
+ INSTALLED_APPS = [
+ # ... other apps ...
+ "openwisp_utils.admin_theme",
+ # all-auth
+ "django.contrib.sites",
+ "allauth",
+ "allauth.account",
+ "allauth.socialaccount",
+ # openwisp2 modules
+ "openwisp_users",
+ # 'myipam', <-- replace without your app-name here
+ # admin
+ "admin_auto_filters",
+ "django.contrib.admin",
+ # rest framework
+ "rest_framework",
+ # Other dependencies
+ "reversion",
+ ]
+
+For more information about how to work with django projects and django
+apps, please refer to the `django documentation
+`_.
+
+2. Install ``openwisp-ipam``
+----------------------------
+
+Install (and add to the requirement of your project) openwisp-ipam:
+
+.. code-block::
+
+ pip install openwisp-ipam
+
+3. Add ``EXTENDED_APPS``
+------------------------
+
+Add the following to your ``settings.py``:
+
+.. code-block:: python
+
+ EXTENDED_APPS = ("openwisp_ipam",)
+
+4. Add ``openwisp_utils.staticfiles.DependencyFinder``
+------------------------------------------------------
+
+Add ``openwisp_utils.staticfiles.DependencyFinder`` to
+``STATICFILES_FINDERS`` in your ``settings.py``:
+
+.. code-block:: python
+
+ STATICFILES_FINDERS = [
+ "django.contrib.staticfiles.finders.FileSystemFinder",
+ "django.contrib.staticfiles.finders.AppDirectoriesFinder",
+ "openwisp_utils.staticfiles.DependencyFinder",
+ ]
+
+5. Add ``openwisp_utils.loaders.DependencyLoader``
+--------------------------------------------------
+
+Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES`` in your
+``settings.py``, but ensure it comes before
+``django.template.loaders.app_directories.Loader``:
+
+.. code-block:: python
+
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "OPTIONS": {
+ "loaders": [
+ "django.template.loaders.filesystem.Loader",
+ "openwisp_utils.loaders.DependencyLoader",
+ "django.template.loaders.app_directories.Loader",
+ ],
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ }
+ ]
+
+6. Inherit the AppConfig Class
+------------------------------
+
+Please refer to the following files in the sample app of the test project:
+
+- `sample_ipam/__init__.py
+ `_.
+- `sample_ipam/apps.py
+ `_.
+
+You have to replicate and adapt that code in your project.
+
+For more information regarding the concept of ``AppConfig`` please refer
+to the `"Applications" section in the django documentation
+`_.
+
+7. Create your Custom Models
+----------------------------
+
+For the purpose of showing an example, we added a simple "details" field
+to the `models of the sample app in the test project
+`_.
+
+You can add fields in a similar way in your ``models.py`` file.
+
+**Note**: for doubts regarding how to use, extend or develop models please
+refer to the `"Models" section in the django documentation
+`_.
+
+8. Add Swapper Configurations
+-----------------------------
+
+Once you have created the models, add the following to your
+``settings.py``:
+
+.. code-block:: python
+
+ # Setting models for swapper module
+ OPENWISP_IPAM_IPADDRESS_MODEL = "myipam.IpAddress"
+ OPENWISP_IPAM_SUBNET_MODEL = "myipam.Subnet"
+
+Substitute ``myipam`` with the name you chose in step 1.
+
+9. Create Database Migrations
+-----------------------------
+
+Create and apply database migrations:
+
+.. code-block::
+
+ ./manage.py makemigrations
+ ./manage.py migrate
+
+For more information, refer to the `"Migrations" section in the django
+documentation
+`_.
+
+10. Create the Admin
+--------------------
+
+Refer to the `admin.py file of the sample app
+`_.
+
+To introduce changes to the admin, you can do it in two main ways which
+are described below.
+
+**Note**: for more information regarding how the django admin works, or
+how it can be customized, please refer to `"The django admin site" section
+in the django documentation
+`_.
+
+1. Monkey Patching
+~~~~~~~~~~~~~~~~~~
+
+If the changes you need to add are relatively small, you can resort to
+monkey patching.
+
+For example:
+
+.. code-block:: python
+
+ from openwisp_ipam.admin import IpAddressAdmin, SubnetAdmin
+
+ SubnetAdmin.app_label = "sample_ipam"
+
+2. Inheriting Admin Classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you need to introduce significant changes and/or you don't want to
+resort to monkey patching, you can proceed as follows:
+
+.. code-block:: python
+
+ from django.contrib import admin
+ from openwisp_ipam.admin import (
+ IpAddressAdmin as BaseIpAddressAdmin,
+ SubnetAdmin as BaseSubnetAdmin,
+ )
+ from swapper import load_model
+
+ IpAddress = load_model("openwisp_ipam", "IpAddress")
+ Subnet = load_model("openwisp_ipam", "Subnet")
+
+ admin.site.unregister(IpAddress)
+ admin.site.unregister(Subnet)
+
+
+ @admin.register(IpAddress)
+ class IpAddressAdmin(BaseIpAddressAdmin):
+ # add your changes here
+ pass
+
+
+ @admin.register(Subnet)
+ class SubnetAdmin(BaseSubnetAdmin):
+ app_label = "myipam"
+ # add your changes here
+
+Substitute ``myipam`` with the name you chose in step 1.
+
+11. Create Root URL Configuration
+---------------------------------
+
+.. code-block:: python
+
+ from .sample_ipam import views as api_views
+ from openwisp_ipam.urls import get_urls
+
+ urlpatterns = [
+ # ... other urls in your project ...
+ # openwisp-ipam urls
+ # path('', include(get_urls(api_views))) <-- Use only when changing API views (dicussed below)
+ path("", include("openwisp_ipam.urls")),
+ ]
+
+For more information about URL configuration in django, please refer to
+the `"URL dispatcher" section in the django documentation
+`_.
+
+12. Import the Automated Tests
+------------------------------
+
+When developing a custom application based on this module, it's a good
+idea to import and run the base tests too, so that you can be sure the
+changes you're introducing are not breaking some of the existing features
+of *openwisp-ipam*.
+
+In case you need to add breaking changes, you can overwrite the tests
+defined in the base classes to test your own behavior.
+
+See the `tests of the sample app
+`_
+to find out how to do this.
+
+You can then run tests with:
+
+.. code-block::
+
+ # the --parallel flag is optional
+ ./manage.py test --parallel myipam
+
+Substitute ``myipam`` with the name you chose in step 1.
+
+For more information about automated tests in django, please refer to
+`"Testing in Django"
+`_.
+
+Other Base Classes That Can be Inherited and Extended
+-----------------------------------------------------
+
+The following steps are not required and are intended for more advanced
+customization.
+
+1. Extending the API Views
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The API view classes can be extended into other django applications as
+well. Note that it is not required for extending openwisp-ipam to your app
+and this change is required only if you plan to make changes to the API
+views.
+
+Create a view file as done in `views.py
+`_.
+
+For more information about django views, please refer to the `views
+section in the django documentation
+`_.
diff --git a/docs/developer/index.rst b/docs/developer/index.rst
new file mode 100644
index 0000000..e84b7ae
--- /dev/null
+++ b/docs/developer/index.rst
@@ -0,0 +1,14 @@
+Developer Docs
+==============
+
+.. include:: ../partials/developer-docs.rst
+
+.. toctree::
+ :maxdepth: 2
+
+ ./installation.rst
+ ./extending.rst
+
+Other useful resources:
+
+ - :doc:`../user/rest-api`
diff --git a/docs/developer/installation.rst b/docs/developer/installation.rst
new file mode 100644
index 0000000..a97a8d8
--- /dev/null
+++ b/docs/developer/installation.rst
@@ -0,0 +1,81 @@
+Developer Installation Instructions
+===================================
+
+.. include:: ../partials/developer-docs.rst
+
+.. contents:: **Table of contents**:
+ :depth: 2
+ :local:
+
+Installing for Development
+--------------------------
+
+Install sqlite:
+
+.. code-block:: shell
+
+ sudo apt-get install sqlite3 libsqlite3-dev openssl libssl-dev
+
+Install your forked repo:
+
+.. code-block:: shell
+
+ git clone git://github.com//openwisp-ipam
+ cd openwisp-ipam/
+ pip install -e .
+
+Install test requirements:
+
+.. code-block:: shell
+
+ pip install -r requirements-test.txt
+
+Create database:
+
+.. code-block:: shell
+
+ cd tests/
+ ./manage.py migrate
+ ./manage.py createsuperuser
+
+Launch development server:
+
+.. code-block:: shell
+
+ ./manage.py runserver
+
+You can access the admin interface at ``http://127.0.0.1:8000/admin/``.
+
+Run tests with:
+
+.. code-block:: shell
+
+ # --parallel and --keepdb are optional but help to speed up the operation
+ ./runtests.py --parallel --keepdb
+
+Alternative Sources
+-------------------
+
+Pypi
+~~~~
+
+To install the latest stable version from PyPI:
+
+.. code-block:: shell
+
+ pip install openwisp-ipam
+
+Github
+~~~~~~
+
+To install the latest development version tarball via HTTPs:
+
+.. code-block:: shell
+
+ pip install https://github.com/openwisp/openwisp-ipam/tarball/master
+
+Alternatively you can use the git protocol:
+
+.. code-block:: shell
+
+ pip install -e git+git://github.com/openwisp/openwisp-ipam#egg=openwisp_ipam
diff --git a/docs/images/architecture-v2-openwisp-ipam.png b/docs/images/architecture-v2-openwisp-ipam.png
new file mode 100644
index 0000000..3b9847a
Binary files /dev/null and b/docs/images/architecture-v2-openwisp-ipam.png differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..8db6bdf
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,56 @@
+IPAM
+====
+
+.. seealso::
+
+ **Source code**: `github.com/openwisp/openwisp-ipam
+ `_.
+
+.. image:: https://github.com/openwisp/openwisp-ipam/raw/docs/docs/subnet_demo.gif
+ :target: https://github.com/openwisp/openwisp-ipam/raw/docs/docs/subnet_demo.gif
+ :alt: Feature Highlights
+
+OpenWISP IPAM provides IP Address Management (IPAM) features, refer to
+:doc:`user/intro` for a complete overview. As a core dependency of the
+:doc:`OpenWISP Controller `, it facilitates the
+automatic provisioning of IP addresses for VPNs such as :doc:`Wireguard
+` and :doc:`Zerotier
+`, and allows to implement the :doc:`Subnet
+Division Rules feature `.
+
+In addition to its integration with the OpenWISP ecosystem, OpenWISP IPAM
+can be used as a standalone Django app: developers proficient in Python
+and Django can leverage this module independently to enhance their
+projects, for more details on this subject please refer to the
+:doc:`developer documentation `.
+
+The following diagram illustrates the role of the IPAM module within the
+OpenWISP architecture.
+
+.. figure:: images/architecture-v2-openwisp-ipam.png
+ :target: ../_images/architecture-v2-openwisp-ipam.png
+ :align: center
+ :alt: OpenWISP Architecture: IPAM module
+
+ **OpenWISP Architecture: highlighted IPAM module**
+
+.. important::
+
+ For an enhanced viewing experience, open the image above in a new
+ browser tab.
+
+ Refer to :doc:`/general/architecture` for more information.
+
+.. toctree::
+ :caption: IPAM Usage Docs
+ :maxdepth: 1
+
+ ./user/intro.rst
+ ./user/import-export-subnets.rst
+ ./user/rest-api.rst
+
+.. toctree::
+ :caption: IPAM Developer Docs
+ :maxdepth: 2
+
+ Developer Docs Index
diff --git a/docs/partials/developer-docs.rst b/docs/partials/developer-docs.rst
new file mode 100644
index 0000000..26fe9fa
--- /dev/null
+++ b/docs/partials/developer-docs.rst
@@ -0,0 +1,12 @@
+.. note::
+
+ This documentation page is aimed at developers who want to customize,
+ change or extend the code of OpenWISP IPAM in order to modify its
+ behavior (eg: for personal or commercial purposes or to fix a bug,
+ implement a new feature or contribute to the project in general).
+
+ If you aren't a developer and you are looking for information on how
+ to use OpenWISP, please refer to:
+
+ - :doc:`General OpenWISP Quickstart `
+ - :doc:`OpenWISP IPAM Docs `
diff --git a/docs/user/import-export-subnets.rst b/docs/user/import-export-subnets.rst
new file mode 100644
index 0000000..c70bca1
--- /dev/null
+++ b/docs/user/import-export-subnets.rst
@@ -0,0 +1,72 @@
+Exporting and Importing Subnet
+==============================
+
+One can easily import and export `Subnet` data and it's Ip Addresses using
+`openwisp-ipam`. This works for both IPv4 and IPv6 types of networks.
+
+.. contents:: **Table of contents**:
+ :depth: 2
+ :local:
+
+Exporting
+---------
+
+Data can be exported via the admin interface or by using a management
+command. The exported data is in `.csv` file format.
+
+From Management Command
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: shell
+
+ ./manage.py export_subnet
+
+This would export the subnet if it exists on the database.
+
+From Admin Interface
+~~~~~~~~~~~~~~~~~~~~
+
+Data can be exported from the admin interface by just clicking on the
+export button on the subnet's admin change view.
+
+.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/export.png
+
+Importing
+---------
+
+Data can be imported via the admin interface or by using a management
+command. The imported data file can be in `.csv` and `.xlsx` format. While
+importing data for ip addresses, the system checks if the subnet specified
+in the import file exists or not. If the subnet does not exists it will be
+created while importing data.
+
+From Management Command
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: shell
+
+ ./manage.py import_subnet --file=
+
+From Admin Interface
+~~~~~~~~~~~~~~~~~~~~
+
+Data can be imported from the admin interface by just clicking on the
+import button on the subnet view.
+
+.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/import.png
+
+CSV File Format
+===============
+
+Follow the following structure while creating `csv` file to import data.
+
+.. code-block:: text
+
+ Subnet Name
+ Subnet Value
+ Organization Slug
+
+ ip_address,description
+ ,
+ ,
+ ,
diff --git a/docs/user/intro.rst b/docs/user/intro.rst
new file mode 100644
index 0000000..552a828
--- /dev/null
+++ b/docs/user/intro.rst
@@ -0,0 +1,17 @@
+IPAM: Features
+==============
+
+OpenWISP IPAM provides the following capabilities:
+
+- IPv4 and IPv6 IP address management
+- IPv4 and IPv6 Subnet management
+- :doc:`CSV Import and Export of subnets ` and
+ their IPs
+- Automatic free space display for all subnets
+- IP request module
+- :doc:`REST API ` for CRUD operations and main features
+- Possibility to search for an IP or subnet
+- Visual display for a specific subnet
+
+ .. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/visual-display.png
+ :target: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/visual-display.png
diff --git a/docs/user/rest-api.rst b/docs/user/rest-api.rst
new file mode 100644
index 0000000..544f7dd
--- /dev/null
+++ b/docs/user/rest-api.rst
@@ -0,0 +1,294 @@
+REST API
+========
+
+.. contents:: **Table of contents**:
+ :depth: 1
+ :local:
+
+.. _ipam_live_documentation:
+
+Live Documentation
+------------------
+
+.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/api-docs.png
+ :target: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/api-docs.png
+
+A general live API documentation (following the OpenAPI specification) is
+available at ``/api/v1/docs/``.
+
+.. _ipam_browsable_web_interface:
+
+Browsable Web Interface
+-----------------------
+
+.. image:: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/api-ui.png
+ :target: https://raw.githubusercontent.com/openwisp/openwisp-ipam/docs/docs/api-ui.png
+
+Additionally, opening any of the endpoints :ref:`ipam_list_endpoints`
+directly in the browser will show the `browsable API interface of
+Django-REST-Framework
+`_, which
+makes it even easier to find out the details of each endpoint.
+
+Authentication
+--------------
+
+See openwisp-users: :ref:`authenticating_rest_api`.
+
+When browsing the API via the :ref:`ipam_live_documentation` or the
+:ref:`ipam_browsable_web_interface`, you can also use the session
+authentication by logging in the django admin.
+
+API Throttling
+--------------
+
+To override the default API throttling settings, add the following to your
+``settings.py`` file:
+
+.. code-block:: python
+
+ REST_FRAMEWORK = {
+ "DEFAULT_THROTTLE_RATES": {
+ "ipam": "100/hour",
+ }
+ }
+
+The rate descriptions used in ``DEFAULT_THROTTLE_RATES`` may include
+``second``, ``minute``, ``hour`` or ``day`` as the throttle period.
+
+Pagination
+----------
+
+All *list* endpoints support the ``page_size`` parameter that allows
+paginating the results in conjunction with the ``page`` parameter.
+
+.. code-block:: text
+
+ GET /api/v1//?page_size=10
+ GET /api/v1//?page_size=10&page=2
+
+.. _ipam_list_endpoints:
+
+List of Endpoints
+-----------------
+
+Since the detailed explanation is contained in the
+:ref:`ipam_live_documentation` and in the
+:ref:`ipam_browsable_web_interface` of each endpoint, here we'll provide
+just a list of the available endpoints, for further information please
+open the URL of the endpoint in your browser.
+
+Get Next Available IP
+~~~~~~~~~~~~~~~~~~~~~
+
+Fetch the next available IP address under a specific subnet.
+
+GET
++++
+
+Returns the next available IP address under a subnet.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//get-next-available-ip/
+
+Request IP
+~~~~~~~~~~
+
+A model method to create and fetch the next available IP address record
+under a subnet.
+
+POST
+++++
+
+Creates a record for next available IP address and returns JSON data of
+that record.
+
+.. code-block:: text
+
+ POST /api/v1/ipam/subnet//request-ip/
+
+=========== =======================================
+Param Description
+=========== =======================================
+description Optional description for the IP address
+=========== =======================================
+
+Response
+++++++++
+
+.. code-block:: json
+
+ {
+ "ip_address": "ip_address",
+ "subnet": "subnet_uuid",
+ "description": "optional description"
+ }
+
+Subnet IP Address List/Create
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An api endpoint to retrieve or create IP addresses under a specific
+subnet.
+
+GET
++++
+
+Returns the list of IP addresses under a particular subnet.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//ip-address/
+
+POST
+++++
+
+Create a new ``IP Address``.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//ip-address/
+
+=========== =======================================
+Param Description
+=========== =======================================
+ip_address IPv6/IPv4 address value
+subnet Subnet UUID
+description Optional description for the IP address
+=========== =======================================
+
+Subnet List/Create
+~~~~~~~~~~~~~~~~~~
+
+An api endpoint to create or retrieve the list of subnet instances.
+
+GET
++++
+
+Returns the list of ``Subnet`` instances.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet/
+
+POST
+++++
+
+Create a new ``Subnet``.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet/
+
+============= =======================================
+Param Description
+============= =======================================
+subnet Subnet value in CIDR format
+master_subnet Master Subnet UUID
+description Optional description for the IP address
+============= =======================================
+
+Subnet Detail
+~~~~~~~~~~~~~
+
+An api endpoint for retrieving, updating or deleting a subnet instance.
+
+GET
++++
+
+Get details of a ``Subnet`` instance
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//
+
+DELETE
+++++++
+
+Delete a ``Subnet`` instance
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//
+
+PUT
++++
+
+Update details of a ``Subnet`` instance.
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//
+
+============= =======================================
+Param Description
+============= =======================================
+subnet Subnet value in CIDR format
+master_subnet Master Subnet UUID
+description Optional description for the IP address
+============= =======================================
+
+IP Address Detail
+~~~~~~~~~~~~~~~~~
+
+An api endpoint for retrieving, updating or deleting a IP address
+instance.
+
+GET
++++
+
+Get details of an ``IP address`` instance.
+
+.. code-block:: text
+
+ /api/v1/ipam/ip-address//
+
+DELETE
+++++++
+
+Delete an ``IP address`` instance.
+
+.. code-block:: text
+
+ /api/v1/ipam/ip-address//
+
+PUT
++++
+
+Update details of an ``IP address`` instance.
+
+.. code-block:: text
+
+ /api/v1/ipam/ip-address//
+
+=========== =======================================
+Param Description
+=========== =======================================
+ip_address IPv6/IPv4 value
+subnet Subnet UUID
+description Optional description for the IP address
+=========== =======================================
+
+Export Subnet
+~~~~~~~~~~~~~
+
+View to export subnet data.
+
+POST
+++++
+
+.. code-block:: text
+
+ /api/v1/ipam/subnet//export/
+
+Import Subnet
+~~~~~~~~~~~~~
+
+View to import subnet data.
+
+POST
+++++
+
+.. code-block:: text
+
+ /api/v1/ipam/import-subnet/
diff --git a/pyproject.toml b/pyproject.toml
index 892de1a..bab7ac1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,7 +8,7 @@ omit = [
]
[tool.docstrfmt]
-extend_exclude = ["**/*.py", "README.rst"]
+extend_exclude = ["**/*.py"]
[tool.isort]
known_third_party = ["django"]