From f93b5d1eda3b083cae2c27ccef98c21d6d81996d Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 28 Feb 2022 15:44:26 +0100 Subject: [PATCH 1/3] upgrade to django 4.0 --- Lagerregal/urls.py | 6 +- api/views.py | 2 +- devicedata/ajax.py | 2 +- devicedata/providers/opsi.py | 2 +- devicedata/providers/puppet.py | 2 +- devicegroups/models.py | 2 +- devicegroups/views.py | 2 +- devices/forms.py | 2 +- devices/models.py | 2 +- devices/views.py | 2 +- devicetags/models.py | 2 +- devicetags/views.py | 2 +- devicetypes/models.py | 2 +- devicetypes/views.py | 2 +- history/views.py | 2 +- locations/models.py | 2 +- locations/views.py | 2 +- mail/models.py | 3 +- mail/views.py | 2 +- main/models.py | 2 +- main/views.py | 2 +- network/forms.py | 2 +- network/models.py | 2 +- network/views.py | 2 +- package-lock.json | 101 ++++++++++++++++++++++++++++++++- package.json | 4 +- requirements.txt | 8 +-- users/forms.py | 8 +-- users/models.py | 2 +- users/views.py | 2 +- 30 files changed, 139 insertions(+), 39 deletions(-) diff --git a/Lagerregal/urls.py b/Lagerregal/urls.py index 2db2de73..26debf40 100644 --- a/Lagerregal/urls.py +++ b/Lagerregal/urls.py @@ -3,12 +3,14 @@ from django.contrib.auth import views as auth_views from django.contrib.auth.decorators import login_required from django.urls import include -from django.urls import path +from django.urls import path, re_path from django.views.decorators.clickjacking import xframe_options_exempt from django.views.i18n import JavaScriptCatalog from django.views.static import serve +from django.views.generic import RedirectView from rest_framework.urlpatterns import format_suffix_patterns +from favicon import conf from api import views as api_views from devicedata import ajax as devicedata_ajax @@ -163,7 +165,7 @@ path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')), - path('', include('favicon.urls')), + re_path(r'^favicon\.ico$', RedirectView.as_view(url=conf.FAVICON_PATH, permanent=True), name='favicon'), path('devices_ajax/add_widget/', login_required(main_ajax.WidgetAdd.as_view()), name="widget_add"), path('devices_ajax/remove_widget/', login_required(main_ajax.WidgetRemove.as_view()), name="widget_remove"), diff --git a/api/views.py b/api/views.py index 25d5bb06..08c81040 100644 --- a/api/views.py +++ b/api/views.py @@ -5,7 +5,7 @@ from django.contrib.auth.models import Group from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import rest_framework.reverse from rest_framework import generics diff --git a/devicedata/ajax.py b/devicedata/ajax.py index f04ff59c..10535b73 100644 --- a/devicedata/ajax.py +++ b/devicedata/ajax.py @@ -5,7 +5,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import render from django.utils.timesince import timesince -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic.base import View from devicedata.generic import _get_provider diff --git a/devicedata/providers/opsi.py b/devicedata/providers/opsi.py index 43ee9fb9..1f6b3170 100644 --- a/devicedata/providers/opsi.py +++ b/devicedata/providers/opsi.py @@ -1,6 +1,6 @@ from django.conf import settings from django.core.exceptions import ObjectDoesNotExist -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from devicedata.providers.base_provider import BaseDeviceInfo from devicedata.providers.base_provider import BaseProvider diff --git a/devicedata/providers/puppet.py b/devicedata/providers/puppet.py index 36d702f4..dc5d5f02 100644 --- a/devicedata/providers/puppet.py +++ b/devicedata/providers/puppet.py @@ -6,7 +6,7 @@ from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import requests diff --git a/devicegroups/models.py b/devicegroups/models.py index 145507e0..e1b15772 100644 --- a/devicegroups/models.py +++ b/devicegroups/models.py @@ -1,6 +1,6 @@ from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from reversion import revisions as reversion diff --git a/devicegroups/views.py b/devicegroups/views.py index b63aa0f9..e374906a 100644 --- a/devicegroups/views.py +++ b/devicegroups/views.py @@ -2,7 +2,7 @@ from django.db.models import Q from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/devices/forms.py b/devices/forms.py index 37d616d3..eaaf700e 100644 --- a/devices/forms.py +++ b/devices/forms.py @@ -7,7 +7,7 @@ from django.db.utils import OperationalError from django.db.utils import ProgrammingError from django.shortcuts import get_object_or_404 -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django_select2.forms import Select2MultipleWidget from django_select2.forms import Select2Widget diff --git a/devices/models.py b/devices/models.py index 0b6f49b0..271ff888 100644 --- a/devices/models.py +++ b/devices/models.py @@ -5,7 +5,7 @@ from django.db.models import Q from django.urls import reverse from django.utils.timezone import utc -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import reversion diff --git a/devices/views.py b/devices/views.py index a38ecb61..e3aeccb8 100644 --- a/devices/views.py +++ b/devices/views.py @@ -24,7 +24,7 @@ from django.urls import reverse_lazy from django.utils import timezone from django.utils.timesince import timesince -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/devicetags/models.py b/devicetags/models.py index 39c5e462..2fb077a8 100644 --- a/devicetags/models.py +++ b/devicetags/models.py @@ -1,6 +1,6 @@ from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from devices.models import Device diff --git a/devicetags/views.py b/devicetags/views.py index bffad4bd..c6f01281 100644 --- a/devicetags/views.py +++ b/devicetags/views.py @@ -3,7 +3,7 @@ from django.shortcuts import render from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import FormView diff --git a/devicetypes/models.py b/devicetypes/models.py index 56485154..ca916d9f 100644 --- a/devicetypes/models.py +++ b/devicetypes/models.py @@ -1,6 +1,6 @@ from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from reversion import revisions as reversion diff --git a/devicetypes/views.py b/devicetypes/views.py index d7ad9d0b..7c517b4d 100644 --- a/devicetypes/views.py +++ b/devicetypes/views.py @@ -4,7 +4,7 @@ from django.shortcuts import render from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/history/views.py b/history/views.py index 762fc591..2f136609 100644 --- a/history/views.py +++ b/history/views.py @@ -5,7 +5,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView from django.views.generic import UpdateView diff --git a/locations/models.py b/locations/models.py index 559c5137..8cf303ec 100644 --- a/locations/models.py +++ b/locations/models.py @@ -1,6 +1,6 @@ from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import reversion diff --git a/locations/views.py b/locations/views.py index 030ef661..7674a001 100644 --- a/locations/views.py +++ b/locations/views.py @@ -5,7 +5,7 @@ from django.shortcuts import render from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/mail/models.py b/mail/models.py index f981dfb1..9b5596a2 100644 --- a/mail/models.py +++ b/mail/models.py @@ -4,8 +4,7 @@ from django.core.mail import EmailMessage from django.db import models from django.urls import reverse -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import pystache diff --git a/mail/views.py b/mail/views.py index 83450520..0cb9d3e8 100644 --- a/mail/views.py +++ b/mail/views.py @@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404 from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/main/models.py b/main/models.py index aa1d0c0d..097eb9b2 100644 --- a/main/models.py +++ b/main/models.py @@ -1,6 +1,6 @@ from django.db import models from django.db.models.signals import post_save -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from users.models import Lageruser diff --git a/main/views.py b/main/views.py index 91f3a603..0015afd3 100644 --- a/main/views.py +++ b/main/views.py @@ -2,7 +2,7 @@ from django.db.models import Q from django.shortcuts import redirect -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView from reversion.models import Revision diff --git a/network/forms.py b/network/forms.py index 6f7f836b..f4e00926 100644 --- a/network/forms.py +++ b/network/forms.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django_select2.forms import Select2MultipleWidget diff --git a/network/models.py b/network/models.py index 67556efd..06e250f0 100644 --- a/network/models.py +++ b/network/models.py @@ -1,6 +1,6 @@ from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from reversion import revisions as reversion diff --git a/network/views.py b/network/views.py index 71eb1ade..46b5b60c 100644 --- a/network/views.py +++ b/network/views.py @@ -4,7 +4,7 @@ from django.shortcuts import render from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView diff --git a/package-lock.json b/package-lock.json index 7ceba260..2e78a201 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,106 @@ { "name": "lagerregal", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "name": "lagerregal", + "license": "BSD-3-Clause", + "dependencies": { + "alpinejs": "^2.8.2", + "bootstrap": "^4.6.0", + "bootswatch": "^4.6.0", + "datatables.net": "^1.10.24", + "datatables.net-bs4": "^1.10.24", + "font-awesome": "^4.7.0", + "jquery": "^3.6.0", + "jquery-ui-dist": "^1.12.1", + "noty": "^2.4.1", + "popper.js": "^1.16.1", + "print-js": "^1.5.0", + "select2": "^4.0.13", + "timeago": "^1.6.7" + } + }, + "node_modules/alpinejs": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-2.8.2.tgz", + "integrity": "sha512-5yOUtckn4CBp0qsHpo2qgjZyZit84uXvHbB7NJ27sn4FA6UlFl2i9PGUAdTXkcbFvvxDJBM+zpOD8RuNYFvQAw==" + }, + "node_modules/bootstrap": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", + "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==" + }, + "node_modules/bootswatch": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-4.6.0.tgz", + "integrity": "sha512-Yr6YqFBC8jwTzoJoLViYlvO97IhPWGqZEm+6FXHfD/G6gbUok6sZkdXxdh4Zb6iCGEwr9p7zGCn38yKQD/bh2Q==" + }, + "node_modules/datatables.net": { + "version": "1.10.25", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.25.tgz", + "integrity": "sha512-y0+C7all+MC/h1acwnjErhaJPjYGKpWTvbXrfEUbR8+P+nnhgjNn5nL1udgsTwBObMhlj1KITNBRrM/ZLSoj+Q==", + "dependencies": { + "jquery": ">=1.7" + } + }, + "node_modules/datatables.net-bs4": { + "version": "1.10.25", + "resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.25.tgz", + "integrity": "sha512-leoiWJWxoPKHBNC9dkFRE84PRybQcAI2Aw4UiS5zisROcYRx8YG1uQOTtID4jbqakmbwwXap/c2eH+sdVP5t2w==", + "dependencies": { + "datatables.net": "1.10.25", + "jquery": ">=1.7" + } + }, + "node_modules/font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=", + "engines": { + "node": ">=0.10.3" + } + }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, + "node_modules/jquery-ui-dist": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz", + "integrity": "sha1-XAgV08xvkP9fqvWyaKbiO0ypBPo=" + }, + "node_modules/noty": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/noty/-/noty-2.4.1.tgz", + "integrity": "sha1-Qyf7CYX+k/aq25KfpoB/o8zYagc=" + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, + "node_modules/print-js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/print-js/-/print-js-1.6.0.tgz", + "integrity": "sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==" + }, + "node_modules/select2": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz", + "integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==" + }, + "node_modules/timeago": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/timeago/-/timeago-1.6.7.tgz", + "integrity": "sha512-FikcjN98+ij0siKH4VO4dZ358PR3oDDq4Vdl1+sN9gWz1/+JXGr3uZbUShYH/hL7bMhcTpPbplJU5Tej4b4jbQ==", + "dependencies": { + "jquery": ">=1.5.0 <4.0" + } + } + }, "dependencies": { "alpinejs": { "version": "2.8.2", diff --git a/package.json b/package.json index 2275f521..d3c852f7 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "jquery": "^3.6.0", "jquery-ui-dist": "^1.12.1", "popper.js": "^1.16.1", + "print-js": "^1.5.0", "select2": "^4.0.13", - "timeago": "^1.6.7", - "print-js": "^1.5.0" + "timeago": "^1.6.7" } } diff --git a/requirements.txt b/requirements.txt index 0cad44f3..11af6a90 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -django ~= 3.2.0 -django-reversion >= 2.0.10 -djangorestframework >= 3.6.4 +django ~= 4.0 +django-reversion >= 4.0.0 +djangorestframework >= 3.13.0 Pillow django-oauth-toolkit pytz == 2020.4 @@ -14,4 +14,4 @@ psycopg2-binary faker~=4.1.1 reportlab requests -pdfrw +pdfrw \ No newline at end of file diff --git a/users/forms.py b/users/forms.py index 02575854..02bc51f9 100644 --- a/users/forms.py +++ b/users/forms.py @@ -1,7 +1,7 @@ from django import forms from django.conf import settings -from django.utils.translation import ugettext -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext +from django.utils.translation import gettext_lazy as _ from users.models import DepartmentUser from users.models import Lageruser @@ -20,8 +20,8 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields["timezone"].choices[0] = ("", ugettext("Default ({0})".format(settings.TIME_ZONE))) - self.fields["timezone"].widget.choices[0] = ("", ugettext("Default ({0})".format(settings.TIME_ZONE))) + self.fields["timezone"].choices[0] = ("", gettext("Default ({0})".format(settings.TIME_ZONE))) + self.fields["timezone"].widget.choices[0] = ("", gettext("Default ({0})".format(settings.TIME_ZONE))) class AvatarForm(forms.ModelForm): diff --git a/users/models.py b/users/models.py index 33905845..9c3dd9fd 100644 --- a/users/models.py +++ b/users/models.py @@ -8,7 +8,7 @@ from django.db import models from django.dispatch import receiver from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import pytz from django_auth_ldap.backend import populate_user diff --git a/users/views.py b/users/views.py index 4dd7d82a..af813a89 100644 --- a/users/views.py +++ b/users/views.py @@ -9,7 +9,7 @@ from django.shortcuts import render from django.urls import reverse from django.urls import reverse_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView from django.views.generic import DeleteView from django.views.generic import DetailView From 6fbfd5a08ba7e1de7ac61256b84ac9d404f57b16 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 28 Feb 2022 15:45:23 +0100 Subject: [PATCH 2/3] fix sending emails to groups --- devices/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devices/views.py b/devices/views.py index e3aeccb8..b9e88893 100644 --- a/devices/views.py +++ b/devices/views.py @@ -725,14 +725,14 @@ def form_valid(self, form): try: templates.append(MailTemplate.objects.get(usage="lent")) except: - messages.error(self.request, _('MAIL NOT SENT - Template for lent devices does not exist for your main department')) + messages.error(self.request, _('MAIL NOT SENT - Template for lent devices does not exist')) if form.cleaned_data["room"]: device.room = form.cleaned_data["room"] try: templates.append(MailTemplate.objects.get(usage="room")) except: - messages.error(self.request, _('MAIL NOT SENT - Template for room change does not exist for your main department')) + messages.error(self.request, _('MAIL NOT SENT - Template for room change does not exist')) if templates: for template in templates: template.send(self.request, data={"device": device, "user": self.request.user}) @@ -816,13 +816,13 @@ def form_valid(self, form): try: templates.append(MailTemplate.objects.get(usage="returned")) except: - messages.error(self.request, _('MAIL NOT SENT - Template for returned device does not exist for your main department')) + messages.error(self.request, _('MAIL NOT SENT - Template for returned device does not exist')) if form.cleaned_data["room"]: device.room = form.cleaned_data["room"] try: templates.append(MailTemplate.objects.get(usage="room")) except: - messages.error(self.request, _('MAIL NOT SENT - Template for room change does not exist for your main department')) + messages.error(self.request, _('MAIL NOT SENT - Template for room change does not exist')) if templates: for template in templates: template.send(self.request, data={"device": device, "user": self.request.user}) From 08a59c2da15afb84760a111e6fd3f68afc7a83a4 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 28 Feb 2022 19:20:30 +0100 Subject: [PATCH 3/3] Basic implementation for baramundi support --- Lagerregal/settings/template_production.py | 10 +- Lagerregal/urls.py | 7 +- README.md | 2 +- devicedata/ajax.py | 7 +- devicedata/generic.py | 4 +- devicedata/providers/baramundi.py | 132 ++++++++++++++++++ devicedata/providers/base_provider.py | 5 + devicedata/providers/helpers.py | 2 +- devicedata/providers/puppet.py | 8 +- mail/models.py | 1 + templates/base.html | 2 +- templates/devicedata/device_info_json.html | 2 +- templates/devices/detail/device_detail.html | 81 ++--------- templates/devices/detail/device_detail.js | 1 + .../detail/device_detail_table_entry.html | 13 ++ 15 files changed, 189 insertions(+), 88 deletions(-) create mode 100644 devicedata/providers/baramundi.py create mode 100644 templates/devices/detail/device_detail_table_entry.html diff --git a/Lagerregal/settings/template_production.py b/Lagerregal/settings/template_production.py index e87f331b..c6c8d749 100644 --- a/Lagerregal/settings/template_production.py +++ b/Lagerregal/settings/template_production.py @@ -105,7 +105,8 @@ DATA_PROVIDERS = { 'opsi': 'devicedata.providers.opsi.OpsiProvider', - 'puppet': 'devicedata.providers.puppet.PuppetProvide', + 'puppet': 'devicedata.providers.puppet.PuppetProvider', + 'baramundi': 'devicedata.providers.baramundi.BaramundiProvider', } PUPPETDB_SETTINGS = { @@ -124,6 +125,13 @@ "port": "4447", } +BARAMUNDI_SETTINGS = { + "host": "https://baramundi.mpib-berlin.mpg.de", + "port": "443", + "ignore_ssl": True, + "authorization": "" +} + HOST_BASE_DOMAIN = "mpib-berlin.mpg.de" # sample logger diff --git a/Lagerregal/urls.py b/Lagerregal/urls.py index 26debf40..285de65c 100644 --- a/Lagerregal/urls.py +++ b/Lagerregal/urls.py @@ -3,14 +3,15 @@ from django.contrib.auth import views as auth_views from django.contrib.auth.decorators import login_required from django.urls import include -from django.urls import path, re_path +from django.urls import path +from django.urls import re_path from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.generic import RedirectView from django.views.i18n import JavaScriptCatalog from django.views.static import serve -from django.views.generic import RedirectView -from rest_framework.urlpatterns import format_suffix_patterns from favicon import conf +from rest_framework.urlpatterns import format_suffix_patterns from api import views as api_views from devicedata import ajax as devicedata_ajax diff --git a/README.md b/README.md index e590e124..cea8f04d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Features + Generates and prints Dymo labels from templates for inventory stickers + Manage static IP addresses for legacy network environments + Semi-Automatic e-mail delivery (on lending, trashing etc) -+ Optional query and listing for puppet facts or opsi details of a device ++ Optional query and listing of device data from puppet, opsi or baramundi + Permission system for users and public device lists + Themable with bootswatch diff --git a/devicedata/ajax.py b/devicedata/ajax.py index 10535b73..def9933a 100644 --- a/devicedata/ajax.py +++ b/devicedata/ajax.py @@ -45,7 +45,7 @@ def get(request, device): raw_entries = [{"name": entry.name, "type": entry.type, "raw_value": as_nested_list(entry.raw_value)} for entry in device_info.raw_entries] - new_entries = _update_provided_data(device, device_info) + new_entries = _update_provided_data(device, device_info, True) formatted_entries = [{"name": entry.name, "value": entry.formatted_value, "stored_at": timesince(entry.stored_at)} for entry in new_entries] @@ -58,8 +58,11 @@ class DeviceSoftware(View): @staticmethod def get(request, device): device = get_object_or_404(Device, pk=device) + provider = _get_provider(device) + if provider is None: + return JsonResponse({}) try: - software_info = _get_provider(device).get_software_info(device) + software_info = provider.get_software_info(device) except Exception as e: logger.error(e) return HttpResponse(_("Could not load data.")) diff --git a/devicedata/generic.py b/devicedata/generic.py index b3bfcf91..2c1a8ed4 100644 --- a/devicedata/generic.py +++ b/devicedata/generic.py @@ -17,12 +17,12 @@ def _get_provider(device): def _update_provided_data(device, data, force=False): + old_data = device.provided_data.all() if not force: - old_data = device.provided_data.all() if len(old_data) > 0: if (timezone.now() - old_data[0].stored_at).days < 7: return old_data - device.provided_data.all().delete() + old_data.delete() for entry in data.formatted_entries: pd = ProvidedData() pd.device = device diff --git a/devicedata/providers/baramundi.py b/devicedata/providers/baramundi.py new file mode 100644 index 00000000..c8eb7a97 --- /dev/null +++ b/devicedata/providers/baramundi.py @@ -0,0 +1,132 @@ +import base64 +from unicodedata import name + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import gettext_lazy as _ + +import requests + +from devicedata.providers.base_provider import BaseDeviceInfo +from devicedata.providers.base_provider import BaseProvider +from devicedata.providers.base_provider import DeviceInfoEntry +from devicedata.providers.base_provider import FormattedDeviceInfoEntry +from devicedata.providers.helpers import format_bytes + + +class BaramundiDeviceInfo(BaseDeviceInfo): + def format_serialnumber(self): + self.simple_format('SerialNumber', _('Serial Number')) + + def format_hostname(self): + self.simple_format('HostName', _('Hostname')) + + def format_type(self): + self.simple_format('ModelName', _('Type')) + + def format_lastseen(self): + self.simple_format('LastSeen', _('Last Seen')) + + def format_processor(self): + self.simple_format('CPUDescription', _('Processor')) + + def format_memory(self): + entries = self.find_entries("TotalMemory") + if len(entries) > 0: + self.formatted_entries.append( + FormattedDeviceInfoEntry(_("Memory"), format_bytes(entries[0].raw_value * 1024 * 1024))) + + def format_storage(self): + entries = self.find_entries("StorageMedia") + drives = [] + for entry in entries: + for disk in entry.raw_value: + if "ByteSize" in disk and disk["ByteSize"] < 1000000000: + # Smaller than 10gb. This most likely is not a hard drive. + continue + drives.append(disk) + formatted_capacities = "
".join( + ["{0}: {1}".format(drive["Name"], format_bytes(drive["ByteSize"])) for drive in drives]) + self.formatted_entries.append(FormattedDeviceInfoEntry(_("Storage"), formatted_capacities)) + + def format_entries(self): + self.format_serialnumber() + self.format_hostname() + self.format_lastseen() + self.format_processor() + self.format_memory() + self.format_storage() + +class BaramundiProvider(BaseProvider): + name = "baramundi" + + @staticmethod + def __run_query(url): + if not hasattr(settings, "BARAMUNDI_SETTINGS"): + return + + host = settings.BARAMUNDI_SETTINGS['host'] + ":" + str(settings.BARAMUNDI_SETTINGS['port']) + full_url = url %host + if 'authorization' in settings.BARAMUNDI_SETTINGS: + authorization = settings.BARAMUNDI_SETTINGS['authorization'] + else: + authorization = ('{}:{}'.format(settings.BARAMUNDI_SETTINGS['user_name'], settings.BARAMUNDI_SETTINGS['password'])).encode('ascii') + authorization = base64.b64encode(authorization).decode('ascii') + session = requests.Session() + session.headers.update({'Authorization': 'Basic {}'.format(authorization), 'content-type': "application/json; charset=utf-8"}) + + print(full_url, settings.BARAMUNDI_SETTINGS['ignore_ssl'] is not True) + result = session.get(full_url, verify=settings.BARAMUNDI_SETTINGS['ignore_ssl'] is not True) + body = result.json() + if len(body) == 0: + raise ObjectDoesNotExist() + return body + + def _get_device_id(self, device): + if len(device.hostname) > 0: + term = device.hostname + else: + term = '{:06d}'.format(device.id) + try: + data = self.__run_query('https://%s/bConnect/v1.0/search.json?type=endpoint&term=' + term) + print(data) + return data[0]['Id'] + except ObjectDoesNotExist: + print("no object") + return None + except KeyError as e: + print(e) + return None + + def get_device_info(self, device): + if not hasattr(settings, "BARAMUNDI_SETTINGS"): + return + id = self._get_device_id(device) + if id is None: + return + info = self.__run_query('https://%s/bConnect/v1.0/endpoints.json?id=' + id) + device_entries = [] + for key in info: + device_entries.append(DeviceInfoEntry(key, None, info[key])) + return BaramundiDeviceInfo(device, device_entries) + + def get_software_info(self, device): + return + if not hasattr(settings, "BARAMUNDI_SETTINGS"): + return + id = self._get_device_id(device) + if id is None: + return + info = self.__run_query('https://%s/bConnect/v1.0/softwarescanrules.json?id=' + id) + print(info) + return super().get_software_info(device) + + def has_device(self, device): + if not hasattr(settings, "BARAMUNDI_SETTINGS"): + return False + try: + id = self._get_device_id(device) + print(id) + return id is not None and len(id) > 0 + except ObjectDoesNotExist: + return False \ No newline at end of file diff --git a/devicedata/providers/base_provider.py b/devicedata/providers/base_provider.py index 1d48a7d9..40371417 100644 --- a/devicedata/providers/base_provider.py +++ b/devicedata/providers/base_provider.py @@ -12,6 +12,11 @@ class BaseDeviceInfo(ABC): def find_entries(self, entry_type): return [entry for entry in self.raw_entries if entry.type == entry_type] + def simple_format(self, entry_type, name): + entries = self.find_entries(entry_type) + if len(entries) > 0: + self.formatted_entries.append((FormattedDeviceInfoEntry(name, entries[0].raw_value))) + def __init__(self, device, raw_entries): self.device = device self.formatted_entries = [] diff --git a/devicedata/providers/helpers.py b/devicedata/providers/helpers.py index 8061138d..b659f4b5 100644 --- a/devicedata/providers/helpers.py +++ b/devicedata/providers/helpers.py @@ -5,4 +5,4 @@ def format_bytes(size, power=2**10): while size > power: size /= power n += 1 - return "{0:g}{1}".format(size, power_labels[n] + "B") + return "{0:.2f}{1}".format(size, power_labels[n] + "B") diff --git a/devicedata/providers/puppet.py b/devicedata/providers/puppet.py index dc5d5f02..9e140057 100644 --- a/devicedata/providers/puppet.py +++ b/devicedata/providers/puppet.py @@ -28,9 +28,7 @@ def format_serialnumber(self): self.formatted_entries.append(FormattedDeviceInfoEntry(_("Serial Number"), entries[0].raw_value)) def format_type(self): - entries = self.find_entries("sp_machine_name") - if len(entries) > 0: - self.formatted_entries.append(FormattedDeviceInfoEntry(_("Type"), entries[0].raw_value)) + self.simple_format('sp_machine_name', _('Type')) def format_hostname(self): entries = self.find_entries("fqdn") @@ -43,9 +41,7 @@ def format_hostname(self): self.formatted_entries.append(FormattedDeviceInfoEntry(_("Hostname"), entries[0].raw_value)) def format_lastseen(self): - entries = self.find_entries("timestamp") - if len(entries) > 0: - self.formatted_entries.append(FormattedDeviceInfoEntry(_("Last Seen"), entries[0].raw_value)) + self.simple_format('timestamp', _('Last Seen')) def format_processor(self): entries = self.find_entries("processors") diff --git a/mail/models.py b/mail/models.py index 9b5596a2..4686da33 100644 --- a/mail/models.py +++ b/mail/models.py @@ -4,6 +4,7 @@ from django.core.mail import EmailMessage from django.db import models from django.urls import reverse +from django.utils import timezone from django.utils.translation import gettext_lazy as _ import pystache diff --git a/templates/base.html b/templates/base.html index a9855879..383af9a3 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,7 +4,7 @@
{% trans "Loading Device Details..." %}
- +
diff --git a/templates/devices/detail/device_detail.html b/templates/devices/detail/device_detail.html index 5f8a7002..fd36dd99 100644 --- a/templates/devices/detail/device_detail.html +++ b/templates/devices/detail/device_detail.html @@ -166,51 +166,13 @@
{% trans "Manual Data" %}
{% trans "Type" %}
- - - - - - - - - - - - - - - - - - - - - - - - - - - +{% include 'devices/detail/device_detail_table_entry.html' with name='Laggerregal ID' value=device.id %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Inventorynumber' value=device.inventorynumber %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Serialnumber' value=device.serialnumber %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Hostname' value=device.hostname %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Devicetype' value=device.devicetype url='type-detail' url_key=device.devicetype.pk %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Manufacturer' value=device.manufacturer url='manufacturer-detail' url_key=device.manufacturer.pk %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Room' value=device.room url='room-detail' url_key=device.room.pk %} {% if device.used_in %} @@ -227,26 +189,8 @@
{% trans "Manual Data" %}
{% endif %} - - - - - - - - +{% include 'devices/detail/device_detail_table_entry.html' with name='Devicegroup' value=device.devicegroup url='devicegroup-detail' url_key=device.devicegroup.pk %} +{% include 'devices/detail/device_detail_table_entry.html' with name='Department' value=device.department %} {% if device.trashed %} - - - - + {% include 'devices/detail/device_detail_table_entry.html' with name='Trashed on' value=device.trashed %} {% endif %} {% if device.inventoried %} @@ -321,7 +262,7 @@
{% trans "Automatic Data" %} from ago
{% trans "Lagerregal ID" %}{{ device.pk }}
{% trans "Inventorynumber" %}{{ device.inventorynumber }}
{% trans "Serialnumber" %}{{ device.serialnumber }}
{% trans "Hostname" %}{{ device.hostname }}
{% trans "Devicetype" %} - {% if device.devicetype %} - {{ device.devicetype }} - {% else %} - — - {% endif %} -
{% trans "Manufacturer" %} - {% if device.manufacturer %} - {{ device.manufacturer }} - {% else %} - — - {% endif %} -
{% trans "Room" %} - {% if device.room %} - {{ device.room }} - {% else %} - — - {% endif %} -
{% trans "Used in" %}
{% trans "Devicegroup" %} - {% if device.group %} - {{ device.group }} - {% else %} - — - {% endif %} -
{% trans "Department" %} - {% if device.department %} - {{ device.department }} - {% else %} - — - {% endif %} -
{% trans "Short term device" %} @@ -293,10 +237,7 @@
{% trans "Manual Data" %}
{% trans "Trashed on" %}{{ device.trashed }}
-