14731 review changes

This commit is contained in:
Arthur Hanson 2024-07-17 15:21:32 +07:00
parent 657b12cc3e
commit 7594ecc790
4 changed files with 90 additions and 76 deletions

View File

@ -32,6 +32,8 @@ class Plugin:
tag_line: str = '' tag_line: str = ''
description_short: str = '' description_short: str = ''
author: str = '' author: str = ''
homepage_url: str = ''
license_type: str = ''
created: datetime.datetime = None created: datetime.datetime = None
updated: datetime.datetime = None updated: datetime.datetime = None
is_local: bool = False is_local: bool = False
@ -41,7 +43,8 @@ class Plugin:
versions: list[PluginVersion] = field(default_factory=list) versions: list[PluginVersion] = field(default_factory=list)
def get_local_plugins(plugins): def get_local_plugins():
plugins = {}
for plugin_name in settings.PLUGINS: for plugin_name in settings.PLUGINS:
plugin = importlib.import_module(plugin_name) plugin = importlib.import_module(plugin_name)
plugin_config: PluginConfig = plugin.config plugin_config: PluginConfig = plugin.config
@ -62,20 +65,20 @@ def get_local_plugins(plugins):
return plugins return plugins
def get_catalog_plugins(plugins): def get_catalog_plugins():
url = 'https://api.netbox.oss.netboxlabs.com/v1/plugins'
session = requests.Session() session = requests.Session()
plugins = {}
def get_pages(): def get_pages():
# TODO: pagintation is curently broken in API # TODO: pagintation is curently broken in API
payload = {'page': '1', 'per_page': '50'} payload = {'page': '1', 'per_page': '50'}
first_page = session.get(url, params=payload).json() first_page = session.get(settings.PLUGIN_CATALOG_URL, params=payload).json()
yield first_page yield first_page
num_pages = first_page['metadata']['pagination']['last_page'] num_pages = first_page['metadata']['pagination']['last_page']
for page in range(2, num_pages + 1): for page in range(2, num_pages + 1):
payload['page'] = page payload['page'] = page
next_page = session.get(url, params=payload).json() next_page = session.get(settings.PLUGIN_CATALOG_URL, params=payload).json()
yield next_page yield next_page
for page in get_pages(): for page in get_pages():
@ -96,39 +99,43 @@ def get_catalog_plugins(plugins):
is_netboxlabs_supported=version['is_netboxlabs_supported'], is_netboxlabs_supported=version['is_netboxlabs_supported'],
) )
) )
versions = sorted(versions, key=lambda x: x.date, reverse=True)
if data['slug'] in plugins: plugins[data['slug']] = Plugin(
plugins[data['slug']].is_local = False slug=data['slug'],
plugins[data['slug']].is_certified = data['release_latest']['is_certified'] config_name=data['config_name'],
plugins[data['slug']].description_short = data['description_short'] name=data['title_short'],
else: title_long=data['title_long'],
plugins[data['slug']] = Plugin( tag_line=data['tag_line'],
slug=data['slug'], description_short=data['description_short'],
config_name=data['config_name'], author=data['author']['name'] or _('Unknown Author'),
name=data['title_short'], homepage_url=data['homepage_url'],
title_long=data['title_long'], license_type=data['license_type'],
tag_line=data['tag_line'], created=datetime_from_timestamp(data['created_at']),
description_short=data['description_short'], updated=datetime_from_timestamp(data['updated_at']),
author=data['author']['name'] or _('Unknown Author'), is_local=False,
created=datetime_from_timestamp(data['created_at']), is_installed=False,
updated=datetime_from_timestamp(data['updated_at']), is_certified=data['release_latest']['is_certified'],
is_local=False, is_community=not data['release_latest']['is_certified'],
is_installed=False, versions=versions,
is_certified=data['release_latest']['is_certified'], )
is_community=not data['release_latest']['is_certified'],
versions=versions,
)
return plugins return plugins
def get_plugins(): def get_plugins():
if plugins := cache.get('plugins-catalog-feed'): local_plugins = get_local_plugins()
return plugins catalog_plugins = cache.get('plugins-catalog-feed')
if not catalog_plugins:
catalog_plugins = get_catalog_plugins()
cache.set('plugins-catalog-feed', catalog_plugins, 3600)
plugins = {} plugins = catalog_plugins
plugins = get_local_plugins(plugins) for k, v in local_plugins.items():
plugins = get_catalog_plugins(plugins) if k in plugins:
plugins[k].is_local = True
plugins[k].is_installed = True
else:
plugins[k] = v
cache.set('plugins-catalog-feed', plugins, 3600)
return plugins return plugins

View File

@ -617,12 +617,6 @@ class SystemView(UserPassesTestMixin, View):
'rq_worker_count': Worker.count(get_connection('default')), 'rq_worker_count': Worker.count(get_connection('default')),
} }
# Plugins
plugins = [
# Look up app config by package name
apps.get_app_config(plugin.rsplit('.', 1)[-1]) for plugin in settings.PLUGINS
]
# Configuration # Configuration
try: try:
config = ConfigRevision.objects.get(pk=cache.get('config_version')) config = ConfigRevision.objects.get(pk=cache.get('config_version'))
@ -634,9 +628,6 @@ class SystemView(UserPassesTestMixin, View):
if 'export' in request.GET: if 'export' in request.GET:
data = { data = {
**stats, **stats,
'plugins': {
plugin.name: plugin.version for plugin in plugins
},
'config': { 'config': {
k: config.data[k] for k in sorted(config.data) k: config.data[k] for k in sorted(config.data)
}, },
@ -664,10 +655,18 @@ class PluginListView(UserPassesTestMixin, View):
q = request.GET.get('q', None) q = request.GET.get('q', None)
plugins = get_plugins() plugins = get_plugins()
plugins = plugins.values()
if q: if q:
plugins = [v for k, v in plugins.items() if q.casefold() in v['name'].casefold()] plugins = [obj for obj in plugins if q.casefold() in obj.name.casefold()]
else:
plugins = plugins.values() # Sort order should be:
# Installed plugins
# Certified catalog plugins
# Remaining catalog plugins
# With alphabetical sort within each traunch.
plugins = sorted(plugins, key=lambda x: x.name, reverse=False)
plugins = sorted(plugins, key=lambda x: x.is_certified, reverse=True)
plugins = sorted(plugins, key=lambda x: x.is_installed, reverse=True)
table = CatalogPluginTable(plugins, user=request.user) table = CatalogPluginTable(plugins, user=request.user)
table.configure(request) table.configure(request)

View File

@ -769,6 +769,8 @@ STRAWBERRY_DJANGO = {
# Plugins # Plugins
# #
PLUGIN_CATALOG_URL = 'https://api.netbox.oss.netboxlabs.com/v1/plugins'
# Register any configured plugins # Register any configured plugins
for plugin_name in PLUGINS: for plugin_name in PLUGINS:
try: try:

View File

@ -15,6 +15,8 @@
{% block subtitle %} {% block subtitle %}
<div class="text-secondary fs-5"> <div class="text-secondary fs-5">
{{ plugin.tag_line }} {{ plugin.tag_line }}
<a href="{{ plugin.homepage.url }}" target="_blank">Learn more <i class="mdi mdi-launch"></i></a><br />
<strong>License:</strong> {{ plugin.license_type }}
</div> </div>
{% endblock subtitle %} {% endblock subtitle %}
@ -33,16 +35,18 @@ From
</a> </a>
</li> </li>
{% if not plugin.is_local %} {% if not plugin.is_local %}
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="version-history-tab" data-bs-toggle="tab" data-bs-target="#version-history" type="button" role="tab" aria-controls="object-list" aria-selected="false"> <button class="nav-link" id="version-history-tab" data-bs-toggle="tab" data-bs-target="#version-history" type="button" role="tab" aria-controls="object-list" aria-selected="false">
{% trans "Version history" %} {% trans "Version history" %}
</button> </button>
</li> </li>
<li class="nav-item" role="presentation"> {% if plugin.is_community %}
<button class="nav-link" id="install-tab" data-bs-toggle="tab" data-bs-target="#install" type="button" role="tab" aria-controls="object-list" aria-selected="false"> <li class="nav-item" role="presentation">
{% trans "Install" %} <button class="nav-link" id="install-tab" data-bs-toggle="tab" data-bs-target="#install" type="button" role="tab" aria-controls="object-list" aria-selected="false">
</button> {% trans "Install" %}
</li> </button>
</li>
{% endif %}
{% endif %} {% endif %}
</ul> </ul>
@ -51,23 +55,24 @@ From
{% block content %} {% block content %}
<div class="tab-pane show active" id="overview" role="tabpanel" aria-labelledby="overview-tab"> <div class="tab-pane show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
{{ plugin.description_short }} {{ plugin.description_short|markdown }}
</div> </div>
{% if not plugin.is_local %} {% if not plugin.is_local %}
<div class="tab-pane" id="version-history" role="tabpanel" aria-labelledby="version-history-tab"> <div class="tab-pane" id="version-history" role="tabpanel" aria-labelledby="version-history-tab">
<div class="card"> <div class="card">
<div class="htmx-container table-responsive" id="object_list"> <div class="htmx-container table-responsive" id="object_list">
{% include 'htmx/table.html' %} {% include 'htmx/table.html' %}
</div>
</div> </div>
</div> </div>
</div> {% if plugin.is_community %}
<div class="tab-pane" id="install" role="tabpanel" aria-labelledby="install-tab"> <div class="tab-pane" id="install" role="tabpanel" aria-labelledby="install-tab">
<p>You can install this plugin from the command line with PyPi.</p> <p>You can install this plugin from the command line with PyPi.</p>
<p>The following commands may be helpful; always refer to the plugin's own documentation and the Installing a Plugin unit of the NetBox documentation.</p> <p>The following commands may be helpful; always refer to <a href="{{ plugin.homepage_url }}" target="_blank">the plugin's own documentation <i class="mdi mdi-launch"></i></a> and the <a href="https://netboxlabs.com/docs/netbox/en/stable/plugins/installation/" target="_blank">Installing a Plugin unit <i class="mdi mdi-launch"></i></a> of the NetBox documentation.</p>
<p>1. Enter the NetBox virtual environment and install the plugin package:</p> <p>1. Enter the NetBox virtual environment and install the plugin package:</p>
<pre class="block"><code> <pre class="block"><code>
source /opt/netbox/venv/bin/activate source /opt/netbox/venv/bin/activate
pip install {{ plugin.slug }} pip install {{ plugin.slug }}
</code></pre> </code></pre>
@ -76,16 +81,17 @@ pip install {{ plugin.slug }}
PLUGINS= PLUGINS=
"{{ plugin.config_name }}", "{{ plugin.config_name }}",
] ]
</code></pre> </code></pre>
<p>3. Still from the NetBox virtual environment, run database migrations and collect static files:</p> <p>3. Still from the NetBox virtual environment, run database migrations and collect static files:</p>
<pre class="block"><code> <pre class="block"><code>
python3 /opt/netbox/netbox/netbox/manage.py migrate python3 /opt/netbox/netbox/netbox/manage.py migrate
python3 /opt/netbox/netbox/netbox/manage.py collectstatic python3 /opt/netbox/netbox/netbox/manage.py collectstatic
</code></pre> </code></pre>
<p>4. Restart the NetBox services to complete the plugin installation:</p> <p>4. Restart the NetBox services to complete the plugin installation:</p>
<pre class="block"><code> <pre class="block"><code>
sudo systemctl restart netbox netbox-rq sudo systemctl restart netbox netbox-rq
</code></pre> </code></pre>
</div> </div>
{% endif %}
{% endif %} {% endif %}
{% endblock content %} {% endblock content %}