Skip to content

Commit

Permalink
[feature] Added page to show OpenWISP versions #273
Browse files Browse the repository at this point in the history
Closes #273
  • Loading branch information
pandafy committed Nov 27, 2023
1 parent 746b146 commit 5db88c1
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 3 deletions.
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(
'ow-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'
File renamed without changes.
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)

0 comments on commit 5db88c1

Please sign in to comment.