Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Added page to show OpenWISP versions #237 #363

Merged
merged 2 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions openwisp_utils/admin_theme/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@

from django.conf import settings
from django.contrib import admin
from django.shortcuts import render
from django.urls import path
from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy
from django.utils.translation import gettext_lazy as _

from . import settings as app_settings
from .dashboard import get_dashboard_context
from .system_info import (
get_enabled_openwisp_modules,
get_openwisp_version,
get_os_details,
)

logger = logging.getLogger(__name__)

Expand All @@ -30,6 +37,16 @@ def index(self, request, extra_context=None):
context = {'dashboard_enabled': False}
return super().index(request, extra_context=context)

def openwisp_info(self, request, *args, **kwargs):
context = {
'enabled_openwisp_modules': get_enabled_openwisp_modules(),
'system_info': get_os_details(),
'openwisp_version': get_openwisp_version(),
'title': _('System Information'),
'site_title': self.site_title,
}
return render(request, 'admin/openwisp_info.html', context)

def get_urls(self):
autocomplete_view = import_string(app_settings.AUTOCOMPLETE_FILTER_VIEW)
return [
Expand All @@ -38,6 +55,11 @@ def get_urls(self):
self.admin_view(autocomplete_view.as_view(admin_site=self)),
name='ow-auto-filter',
),
path(
'openwisp-system-info/',
self.admin_view(self.openwisp_info),
name='ow-info',
),
] + super().get_urls()


Expand Down
8 changes: 8 additions & 0 deletions openwisp_utils/admin_theme/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ def register_menu_groups(self):
position=10,
config={'label': _('Home'), 'url': '/admin', 'icon': 'ow-dashboard-icon'},
)
register_menu_group(
position=899,
config={
'label': _('System info'),
'url': '/admin/ow-info',
'icon': 'ow-info-icon',
},
)

def modify_admin_theme_settings_links(self):
link_files = []
Expand Down
4 changes: 4 additions & 0 deletions openwisp_utils/admin_theme/static/admin/css/openwisp.css
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,10 @@ body::-webkit-scrollbar {
mask-image: url(../../ui/openwisp/images/dashboard.svg);
-webkit-mask-image: url(../../ui/openwisp/images/dashboard.svg);
}
.ow-info-icon {
mask-image: url(../../ui/openwisp/images/info.svg);
-webkit-mask-image: url(../../ui/openwisp/images/info.svg);
}
.password {
mask-image: url(../../ui/openwisp/images/password.svg);
-webkit-mask-image: url(../../ui/openwisp/images/password.svg);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions openwisp_utils/admin_theme/system_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import platform
from collections import OrderedDict

import pkg_resources
from django.conf import settings
from django.utils.module_loading import import_string

EXTRA_OPENWISP_PACKAGES = ['netdiff', 'netjsonconfig']


def get_installed_openwisp_packages():
dists = pkg_resources.working_set
return {
dist.key: dist.version
for dist in dists
if dist.key.startswith('openwisp') or dist.key in EXTRA_OPENWISP_PACKAGES
}


def get_openwisp_version():
try:
return import_string('openwisp2.__openwisp_version__')
except ImportError:
return None


def get_enabled_openwisp_modules():
enabled_packages = {}
installed_packages = get_installed_openwisp_packages()
extra_packages = {}
for package, version in installed_packages.items():
if package in EXTRA_OPENWISP_PACKAGES:
extra_packages[package] = version
continue
package_name = package.replace('-', '_')
if package_name in settings.INSTALLED_APPS:
enabled_packages[package] = version
else:
# check for sub-apps
for app in settings.INSTALLED_APPS:
if app.startswith(package_name + '.'):
enabled_packages[package] = version
break
enabled_packages = OrderedDict(sorted(enabled_packages.items()))
enabled_packages.update(OrderedDict(sorted(extra_packages.items())))
return enabled_packages


def get_os_details():
uname = platform.uname()
return {
'os_version': uname.version,
'kernel_version': uname.release,
'hardware_platform': uname.machine,
}
18 changes: 18 additions & 0 deletions openwisp_utils/admin_theme/templates/admin/openwisp_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "admin/base_site.html" %}
{% load i18n %}

{% block content %}
{% if openwisp_version %}
<h2>{% trans "OpenWISP Version" %}: {{ openwisp_version }}</h2>
{% endif %}
<h2>{% trans "Installed OpenWISP Modules" %}</h2>
<ul>
{% for name, version in enabled_openwisp_modules.items %}
<li>{{ name }}: {{ version }}</li>
{% endfor %}
</ul>
<h2>{% trans "OS Information" %}</h2>
<p><strong>{% trans "OS version" %}:</strong> {{ system_info.os_version }}</p>
<p><strong>{% trans "Kernel version" %}:</strong> {{ system_info.kernel_version }}</p>
<p><strong>{% trans "Hardware platform" %}:</strong> {{ system_info.hardware_platform }}</p>
{% endblock content %}
2 changes: 1 addition & 1 deletion runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys

sys.path.insert(0, "tests")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "openwisp2.settings")

if __name__ == "__main__":
from django.core.management import execute_from_command_line
Expand Down
Empty file removed tests/__init__.py
Empty file.
2 changes: 1 addition & 1 deletion tests/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "openwisp2.settings")

from django.core.management import execute_from_command_line

Expand Down
1 change: 1 addition & 0 deletions tests/openwisp2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__openwisp_version__ = '23.0.0a'
2 changes: 1 addition & 1 deletion tests/settings.py → tests/openwisp2/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'urls'
ROOT_URLCONF = 'openwisp2.urls'

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
Expand Down
File renamed without changes.
30 changes: 30 additions & 0 deletions tests/test_project/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,33 @@ def test_organization_radius_settings_admin(self):
self.assertEqual(
org_rad_settings.get_field_value('extra_config'), 'no data'
)

@patch(
'openwisp_utils.admin_theme.system_info.settings.INSTALLED_APPS',
['openwisp_users', 'openwisp_utils.admin_theme'],
)
def test_system_information(self, *args):
def _assert_system_information(response):
self.assertContains(response, '<li>openwisp-utils:')
self.assertContains(response, '<li>netjsonconfig:')
self.assertContains(response, '<h2>OS Information</h2>')
self.assertContains(response, '<strong>OS version:</strong>')
self.assertContains(response, '<strong>Kernel version:</strong>')
self.assertContains(response, '<strong>Hardware platform:</strong>')

with self.subTest('Test openwisp version is defined'):
with patch('openwisp2.__openwisp_version__', '23.0.0'):
response = self.client.get(reverse('admin:ow-info'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, '<h2>OpenWISP Version: 23.0.0</h2>')
_assert_system_information(response)

with self.subTest('Test openwisp version is not defined'):
with patch(
'openwisp_utils.admin_theme.system_info.import_string',
side_effect=ImportError,
):
response = self.client.get(reverse('admin:ow-info'))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, '<h2>OpenWISP Version')
_assert_system_information(response)
Loading